代码和文档风格指南 - 遗漏的部分#
这是一个针对 SciPy 的代码和文档指南集合,这些指南在现有的指南和标准中没有明确说明,包括
其中一些是微不足道的,可能看起来不值得讨论,但在许多情况下,这个问题在 SciPy 或 NumPy 代码库的拉取请求审查中出现过。如果一个风格问题足够重要,以至于审查者在合并之前需要更改,那么它就足够重要以至于需要记录——至少对于那些可以通过简单规则解决的问题。
代码风格和指南#
必需的关键字名称#
对于具有多个参数的新函数或方法,除前几个“明显”参数之外的所有参数都应该 _强制_ 使用关键字。这通过在签名中的适当位置包含 *
来实现。
例如,一个在单个数组上操作但具有几个可选参数(例如 method
、flag
、rtol
和 atol
)的函数 foo
将被定义为
def foo(x, *, method='basic', flag=False, rtol=1.5e-8, atol=1-12):
...
要调用 foo
,除 x
之外的所有参数都必须使用显式关键字,例如 foo(arr, rtol=1e-12, method='better')
。
这强制调用者给出显式关键字参数(即使没有使用 *
,大多数用户可能也会这样做),并且意味着可以将附加参数添加到 *
后面的函数中的任何位置;新参数不必添加到现有参数之后。
返回值对象#
对于返回两个或多个概念上不同的元素的新函数或方法,将这些元素返回到一个不可迭代的对象类型中。特别是,不要返回 tuple
、namedtuple
或 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_equal、assert_approx_equal 或 assert_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_raises
或 np.testing.assert_warns
,因为它们不支持 match
参数。
例如,函数 scipy.stats.zmap
应该在输入包含 nan
并且 nan_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
。