代码和文档风格指南 - 缺失的部分#

这是SciPy的编码和文档编写指南的集合,这些指南并未在现有的指南和标准中明确说明,包括

其中一些是微不足道的,可能看起来不值得讨论,但在许多情况下,这个问题已经在SciPy或NumPy仓库的拉取请求审查中出现。如果一个样式问题重要到审查者要求在合并之前进行更改,那么它就足够重要,值得被记录下来——至少在问题可以通过简单规则解决的情况下。

编码风格和指南#

必需的关键字名称#

对于新函数或方法,如果参数超过几个,那么除了前几个“显而易见”的参数外,所有后续参数在给出时都*必须*使用关键字。这是通过在签名中的适当位置包含 * 来实现的。

例如,一个对单个数组进行操作但有多个可选参数(如 methodflagrtolatol)的函数 foo 可以定义为:

def foo(x, *, method='basic', flag=False, rtol=1.5e-8, atol=1-12):
    ...

要调用 foo,除了 x 之外的所有参数都必须使用显式关键字给出,例如 foo(arr, rtol=1e-12, method='better')

这强制调用者提供显式关键字参数(大多数用户即使不使用 * 也可能会这样做),并且 这意味着可以在 * 之后的任何位置向函数添加额外参数;新参数不必添加在现有参数之后。

返回对象#

对于返回两个或更多概念上不同元素的新函数或方法,返回一个不可迭代的对象类型。特别是,不要返回 tuplenamedtuple 或由 scipy._lib._bunch.make_tuple_bunch 生成的“bunch”,后者保留用于向现有函数返回的迭代对象添加新属性。相反,使用现有的返回类(例如 OptimizeResult),或一个新的自定义返回类。

这种返回非可迭代对象的做法迫使调用者更明确地表达他们希望访问的返回对象的元素,并且它使得以向后兼容的方式扩展函数或方法变得更加容易。

如果返回的类是简单且非公开的(即不能从公开模块中导入),它可能像这样被记录:

Returns
-------
res : MyResultObject
    An object with attributes:

    attribute1 : ndarray
        Customized description of attribute 1.
    attribute2 : ndarray
        Customized description of attribute 2.

这里,上面的“MyResultObject”没有链接到外部文档,因为它足够简单,可以在其名称下方立即完全记录所有属性。

一些返回类足够复杂,值得拥有自己的渲染文档。如果返回类是公开的,这是相当标准的,但返回类只有在1)它们旨在被最终用户导入和2)如果它们已经得到论坛批准的情况下才应该是公开的。对于复杂的私有返回类,请参阅 binomtest 如何总结 BinomTestResult 并链接到其文档,并注意 BinomTestResult 不能从 stats 导入。

根据 “MyResultObject” 的复杂性,可以使用普通类或数据类。使用数据类时,不要使用 dataclasses.make_dataclass,而是使用适当的声明。这允许自动补全列出结果对象的所有属性,并改进静态分析。最后,如果有私有属性,请隐藏它们:

@dataclass
class MyResultObject:
    statistic: np.ndarray
    pvalue: np.ndarray
    confidence_interval: ConfidenceInterval
    _rho: np.ndarray = field(repr=False)

numpy.testing 测试函数#

在新代码中,不要使用 assert_almost_equalassert_approx_equalassert_array_almost_equal。这是这些函数的文档字符串中的内容:

It is recommended to use one of `assert_allclose`,
`assert_array_almost_equal_nulp` or `assert_array_max_ulp`
instead of this function for more consistent floating point
comparisons.

有关编写单元测试的更多信息,请参阅 NumPy 测试指南

测试预期的异常/警告#

在编写一个测试函数调用引发异常或发出警告的新测试时,首选风格是使用 pytest.raises/pytest.warns 作为上下文管理器,并在上下文管理器定义的代码块中包含预期引发异常的代码。match 关键字参数与预期消息的足够部分一起给出,以区分同一类别的其他异常/警告。不要使用 np.testing.assert_raisesnp.testing.assert_warns,因为它们不支持 match 参数。

例如,函数 scipy.stats.zmap 在输入包含 nannan_policy"raise" 时应引发 ValueError。对此的测试如下:

scores = np.array([1, 2, 3])
compare = np.array([-8, -3, 2, 7, 12, np.nan])
with pytest.raises(ValueError, match='input contains nan'):
    stats.zmap(scores, compare, nan_policy='raise')

match 参数确保测试不会通过,因为它会引发一个与输入包含 nan 无关的 ValueError