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

这是一系列针对 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 而通过。