在我的新手Python 3.7项目中,许多函数中的参数是numpy.ndarray
。这些必须是二维r x n
矩阵。行维度r
是必不可少的:某些函数需要1 x n
向量,另一些函数需要2 x n
矩阵,其中r
最多三个,甚至可能更多。还为任何r x n
数组定义了函数。 (列尺寸n
对于设计而言不是必需的。)
根据我在Matlab上的经验,此要求可能会引起混乱并且容易出错。因此,我考虑了以下方法:
OneRow
,TwoRows
,ThreeRows
和FourPlusRows
。每个都有一个ndarray
字段,该字段在构造函数中已验证。好处包括类型提示和更好的域建模(如DDD)。缺点是额外的复杂性。 问题:考虑到Python 3中引入的类型提示以及函数式编程的趋势,解决该问题的当前pythonic方法是什么?
答案 0 :(得分:2)
关于Python的最好的事情之一是duck typing,并且Numpy通常与该设计方法非常兼容。假设您具有仅矢量功能vecfunc
。您可以在函数的开头添加一些样板,将任何一维数组膨胀为1 x n
向量:
def vecfunc(arr):
if arr.ndim==1:
arr = arr[None, :]
...function body goes here...
这将避免由于arr
尺寸过小而引起的任何问题,并且在大多数情况下仍可能给出正确的行为。但是,它并不能阻止用户传入r x n x m
数组或15 x n
数组。最终,您将不得不使用方法3.
来处理大量此类问题,并在适当的地方抛出一些异常。例如:
def vecfunc(arr):
if not 0 < arr.ndim < 3:
raise ValueError("arr must have ndim of 1 or 2. arr.ndim: %d" % arr.ndim)
elif arr.ndim==1:
arr = arr[None, :]
如果让您感觉更好,numpy
和scipy
的代码库在许多函数中,何时何地都需要进行基于形状的异常检查。
当然,在开发任何给定功能的最后阶段,您总是可以不添加此类异常检查。您可能会对产生合理行为的输入范围感到惊讶。
如果您对类型注释不满意,可以通过writing your code using Cython获得类似的信息。例如,如果您想要一个仅包含2D整数数组的add
函数,则可以在.pyx
文件中编写以下函数:
import numpy as np
def add(long[:, :] arr1, long[:, :] arr2):
assert tuple(arr1.shape) == tuple(arr2.shape)
result = np.zeros((arr1.shape[0], arr1.shape[1]), dtype=np.long)
cdef long[:, :] result_view = result
for x in range(arr1.shape[0]):
for y in range(arr1.shape[1]):
result_view[x, y] = arr1[x, y] + arr2[x, y]
return result
有关编写和编译Cython的更多详细信息,请参见上面链接的文档。
这并不是真正的强类型输入,而是“类型注释”,但是它可以做您想要的。遗憾的是,我无法找到一种方法来固定单个尺寸的大小,而只能确定尺寸的总数。