我正在尝试使用numpy v1.13中引入的__array_ufunc__方法实现numpy的ufunc与类一起使用。
为简化起见,这是该类的样子:
class toto():
def __init__(self, value, name):
self.value = value
self.name = name
def __add__(self, other):
"""add values and concatenate names"""
return toto(self.value + other.value, self.name + other.name)
def __sub__(self, other):
"""sub values and concatenate names"""
return toto(self.value - other.value, self.name + other.name)
tata = toto(5, "first")
titi = toto(1, "second")
现在,如果我尝试在这两者之间应用np.add,则会得到预期的结果,因为np.add依赖于 add 。但是,如果我打电话说np.exp,则会收到预期的错误:
>>> np.exp(tata)
AttributeError: 'toto' object has no attribute 'exp'
现在,我想做的是“重写”所有numpy的ufunc,以便与该类一起正常工作,而不必重新定义该类中的每个方法(exp(self),log(self)等)。 / p>
我打算使用numpy ufunc的[__array_ufunc __] 1来执行此操作,但由于它没有提供简单的实现示例,因此我并不真正理解该文档。
如果有人对这种看起来很有希望的新功能有任何经验,您能提供一个简单的例子吗?
答案 0 :(得分:0)
如果我使用__array_ufunc__
方法(和__repr__
)扩展您的课程:
class toto():
def __init__(self, value, name):
self.value = value
self.name = name
def __add__(self, other):
"""add values and concatenate names"""
return toto(self.value + other.value, self.name + other.name)
def __sub__(self, other):
"""sub values and concatenate names"""
return toto(self.value - other.value, self.name + other.name)
def __repr__(self):
return f"toto: {self.value}, {self.name}"
def __array_ufunc__(self, *args, **kwargs):
print(args)
print(kwargs)
并尝试一些ufunc
通话:
In [458]: np.exp(tata)
(<ufunc 'exp'>, '__call__', toto: 5, first)
{}
In [459]: np.exp.reduce(tata)
(<ufunc 'exp'>, 'reduce', toto: 5, first)
{}
In [460]: np.multiply.reduce(tata)
(<ufunc 'multiply'>, 'reduce', toto: 5, first)
{}
In [461]: np.exp.reduce(tata,axes=(1,2))
(<ufunc 'exp'>, 'reduce', toto: 5, first)
{'axes': (1, 2)}
In [463]: np.exp.reduce(tata,axes=(1,2),out=np.arange(3))
(<ufunc 'exp'>, 'reduce', toto: 5, first)
{'axes': (1, 2), 'out': (array([0, 1, 2]),)}
显示您的班级收到的信息。显然,您可以执行所需的操作。它可以返回NotImplemented
。我想在您的情况下,它可以将第一个参数应用于您的self.value
,或进行一些自定义计算。
例如,如果我添加
val = args[0].__call__(self.value)
return toto(val, self.name)
我得到:
In [468]: np.exp(tata)
(<ufunc 'exp'>, '__call__', toto: 5, first)
{}
Out[468]: toto: 148.4131591025766, first
In [469]: np.sin(tata)
(<ufunc 'sin'>, '__call__', toto: 5, first)
{}
Out[469]: toto: -0.9589242746631385, first
但是,如果将对象放入数组中,仍然会出现方法错误
In [492]: np.exp(np.array(tata))
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-492-4dc37eb0ffe3> in <module>
----> 1 np.exp(np.array(tata))
AttributeError: 'toto' object has no attribute 'exp'
显然,对象dtype数组上的ufunc
会迭代该数组的元素,并期望使用“相关”方法。对于np.add
(+),它将寻找__add__
方法。对于np.exp
,它寻找一种exp
方法。这个__array_ufunc__
没有被调用。
因此,它似乎更多地用于ndarray
或类似的子类。我认为您正在尝试实现一个可用作对象dtype数组元素的类。