简体   繁体   English

如何用__array_ufunc__覆盖numpy ufunc

[英]How to overide numpy ufunc with __array_ufunc__

I'm trying to implement numpy's ufunc to work with a class, using the __array_ufunc__ method introduced in numpy v1.13. 我正在尝试使用numpy v1.13中引入的__array_ufunc__方法来实现numpy的ufunc来处理类。

To simplify, here's what the class could look like : 为简化起见,这是类的外观:

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")

Now if I try to apply np.add between these two, I get the expected result, as np.add relies on add . 现在,如果我尝试在这两者之间应用np.add,我会得到预期的结果,因为np.add依赖于add But if I call say np.exp, I get an error as expected : 但如果我打电话说np.exp,我会收到预期的错误:

>>> np.exp(tata)
AttributeError: 'toto' object has no attribute 'exp'

Now what I would like to do is to "override" all numpy ufuncs to work smoothly with this class without having to redefine every methods (exp(self), log(self), ...) in the class. 现在我想做的是“覆盖”所有numpy ufunc,以便在这个类中顺利运行,而无需在类中重新定义每个方法(exp(self),log(self),...)。

I was planning to use numpy ufunc's [__array_ufunc__] 1 to do this, but I don't really understand the doc as it doesn't provide a simple exemple of implementation. 我打算使用numpy ufunc的[__array_ufunc__] 1来做这件事,但我并不真正理解这个文档,因为它没有提供一个简单的实现例子。

If anyone has had any experience with this new functionnality that looks promising, could you provide a simple example ? 如果有人对这个看起来很有前景的新功能有任何经验,你能提供一个简单的例子吗?

If I extend your class with a __array_ufunc__ method (and __repr__ ): 如果我有一个扩展您的类__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)

And try some ufunc calls: 并尝试一些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]),)}

That shows the information that your class receives. 这显示了您的班级收到的信息。 Evidently you can do what you want that. 显然你可以做你想做的事。 It can return NotImplemented . 它可以返回NotImplemented I suppose in your case it could apply the first argument to your self.value , or do some custom calculation. 我想在你的情况下它可以将第一个参数应用于你的self.value ,或者做一些自定义计算。

For example if I add 例如,如果我添加

      val = args[0].__call__(self.value) 
      return toto(val, self.name) 

I get: 我明白了:

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

However if I put the object in an array, I still get the method error 但是,如果我将对象放在一个数组中,我仍然会得到方法错误

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'

Apparently ufunc on an object dtype array iterates on the elements of the array, expecting to use a 'relevant' method. 显然ufunc上的数组的元素的对象D型细胞阵列进行迭代,希望使用一个“相关”方法。 For np.add (+) it looks for the __add__ method. 对于np.add (+),它查找__add__方法。 For np.exp it looks for an exp method. 对于np.exp它查找exp方法。 This __array_ufunc__ isn't called. 这个__array_ufunc__没有被调用。

So it looks like it's intended more for a subclass of ndarray , or something equivalent. 所以它看起来更像是ndarray的子类,或类似的东西。 You, I think, are trying to implement a class that can work as elements of an object dtype array. 我认为,您正在尝试实现一个可以作为对象dtype数组元素的类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM