这种情况在我的代码中经常发生。说我有一个功能do_sth(a,b)
,即,只在这个例子中,简单地计算的缘故a+b
,与a,b
任一维numpy
阵列或标量。在很多情况下,我需要函数来广播操作,以便如果两个a,b
都是一维数组,结果将是一个二维数组。我的意思的一个例子如下:
do_sth(1,2) -> 3
do_sth([1,2],0) -> array([1, 2])
do_sth(0,[3,4]) -> array([3, 4])
do_sth([1,2],[3,4]) -> array([[4, 5], [5, 6]])
这有点类似于numpy的ufunc
行为。可能的实现如下:
from numpy import newaxis, atleast_1d
def do_sth(a, b):
"a,b should be either 1d numpy arrays or scalars"
a, b = map(atleast_1d, [a, b])
# the line below mocks a more complicated calculation
res = a[:, newaxis] + b[newaxis]
conds = [a.size == 1, b.size == 1]
if all(conds):
return res[0, 0]
elif any(conds):
return res.ravel()
else:
return res
如您所见,有很多样板。第一个问题是:这是进行输入/输出转换的正确方法吗?是否有任何理由不使用装饰器来处理这种情况?关于此事有任何指导方针吗?
而且,更复杂的计算(在这里被加法运算法则嘲笑)通常会严重失败,例如,如果a
或者b
是具有2D,3D形状的numpy数组。我很难说,计算失败的点并不明显,或者在不同版本的代码中可能随时间变化,并且很难看到错误和错误的输入形状之间的联系。我认为不建议将复杂的计算放在一个try/except
块中(在python EAFP之后))。在这种情况下,在函数开始时检查两个数组的形状是否正确?还有其他选择吗?是否有一个numpy函数,该函数可以同时将输入转换为numpy数组,还可以检查输入是否与一定数量的维兼容,例如asarray_withdim(arr,ndim=5)
?
关于装饰器的使用-我在numpy
代码中没有看到装饰器的大量使用,但是我认为这是因为大多数功能是在装饰器在Python中变得常见之前开发的。如果您可以使其运作起来,那么应该没有任何缺点(但是我不是装饰器或的专家ufunc
)。
未遵循的numpy函数通常具有大量代码,可以将输入压缩为方便的尺寸。然后,它们执行核心操作,然后进行最后的重塑和类型包装。他们可能使用诸如np.atleast_2d之类的功能来确保有足够的尺寸,并使用.reshape(-1,1,1)来压缩多余的尺寸。
np.tensordot
是在输入上执行轴转置和整形以便可以应用已编译的的示例np.dot
。np.insert
开始与一些ndim
和isinstance
测试。特殊情况要尽早处理,而一般情况要留到最后。np.einsum
虽然已经过编译,但是在最终创建nditer
对象并进行计算之前,用C代码进行了大量预处理。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句