如果定义了numpy调用类方法的行为的名称?

时间:2018-02-21 17:45:53

标签: python python-3.x numpy

我注意到如果我在类中使用numpy方法同名的方法,numpy倾向于使用类中定义的方法而不是它自己的方法。例如:

import numpy as np  # using numpy 1.13.1


class PizzaPie:
    def __init__(self, slice_angles: list, topping: str='Cheese'):
        try:
            if sum(slice_angles) > 360:
                raise Exception('A pizza cannot have more than 360 degrees cut '
                             'from it.')
            if sum(slice_angles) == 360:
                self._angles = slice_angles
            else:
                self._angles = slice_angles + [360 - sum(slice_angles)]
        except TypeError:
            # maybe slices are described as complex numbers...?
            total_pie = 0
            for pizza_slice in slice_angles:
                angle = (
                    np.arctan(pizza_slice.imag / pizza_slice.real)
                    * (180 / np.pi)
                )
                total_pie += angle
            if total_pie == 360:
                self._angles = slice_angles
            else:
                # make the left over slice a simple number in degrees.
                self._angles = slice_angles + [360 - total_pie]

        self._topping = topping

    @property
    def topping(self):
        return self._topping

    @topping.setter
    def topping(self, new):
        """Only able to add additional toppings. Removing is too messy."""
        self._topping = self._topping + ', ' + str(new)

    @property
    def slices(self):
        """Returns the number of slices"""
        return len(self.angles)

    def cos(self):
        """Returns the slice number and the cosine of the slice angle as a tuple"""
        return [(sl, np.cos(a*(np.pi/180)))
                for sl, a in enumerate(self._angles)
                ]

    def imag(self):
        """Returns the imaginary portion of the slice angles. Weird huh?"""
        return [(sl, np.imag(a)) for sl, a in enumerate(self._angles)]


mypie = PizzaPie([90, 45, 30, 30, 35])
my_imag_pie = PizzaPie([(20+5j), 90.0, (3+4j)], topping='Dark Matter')

print(np.cos(mypie))
print(np.imag(my_imag_pie))

(当然这段代码完全是虚构的,但它却是我想要做的事情的一个简单例子。想想Imaginary Pizzas很有趣......)

但是你会注意到运行上面的代码将返回绑定方法PizzaPie.imag而不是调用 PizzaPie.imag()(在Python 3.5.3中){{1}在编写PizzaPie.cos时调用。这是numpy 1.13中的一个错误吗?此外,numpy更喜欢使用具有相同名称的类定义方法,这种行为是什么?

旁注:我知道我可以调用np.cos(mypie)然后调用np.cos(mypie),但这很丑陋且不一致。我也担心如果有人使用我的PizzaPie类和更高版本的numpy,它会破坏,我不想支持不同版本的numpy的不同代码,如果可能的话。

1 个答案:

答案 0 :(得分:2)

您的PizzaPie类包含一个数组,但不是ndarray子类。通常,np函数会尝试将其输入转换为数组,然后将该函数应用于该函数,可能会调用相应的方法。

编译了

np.cos,但我们可以通过给它一个列表来了解它尝试做什么,特别是一个不能被制作成简单数字数组的列表:

In [51]: np.cos([np.arange(3),3,[1,2]])
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-51-0d338a087870> in <module>()
----> 1 np.cos([np.arange(3),3,[1,2]])

AttributeError: 'numpy.ndarray' object has no attribute 'cos'
In [52]: np.array([np.arange(3),3,[1,2]])
Out[52]: array([array([0, 1, 2]), 3, list([1, 2])], dtype=object)

np.cos已将输入转换为对象数组,并尝试执行[x.cos() for x in np.array(input)]。对于您的情况,它确实有效,因为您定义了cos方法。

np.imag是Python代码,并尝试返回imag属性(属性)。它假设imag是属性,而不是方法,这就是为什么你得到未评估的方法。

np.imag(val)
    return val.imag
    # or
    return np.asanyarray(val).imag

In [53]: np.imag([np.arange(3),3,[1,2]])
Out[53]: array([0, 0, 0], dtype=object)

尝试将imag设为属性。然后它应该评估。