我注意到如果我在类中使用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的不同代码,如果可能的话。
答案 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
设为属性。然后它应该评估。