在寻找一个不起眼的错误时,我偶然发现了这个最小例子最好的证明:
import numpy as np
class First(object):
def __init__(self):
self.vF = np.vectorize(self.F)
print "First: vF = ", self.vF
def F(self, x):
return x**2
class Second(First):
def __init__(self):
super(Second, self).__init__()
print "Second: vF = ", self.vF
def F(self, x):
raise RuntimeError("Never be here.")
def vF(self, x):
return np.asarray(x)*2
我希望Second
的一个实例有一个明确定义的vF
方法,但似乎并非如此:
arg = (1, 2, 3)
f = First()
print "calling first.vF: ", f.vF(arg)
s = Second()
print "calling second.vF: ", s.vF(arg)
产生
First: vF = <numpy.lib.function_base.vectorize object at 0x23f9310>
calling first.vF: [1 4 9]
First: vF = <numpy.lib.function_base.vectorize object at 0x23f93d0>
Second: vF = <numpy.lib.function_base.vectorize object at 0x23f93d0>
calling second.vF:
Traceback (most recent call last):
...
RuntimeError: Never be here.
因此s.vF
和f.vF
似乎是同一个对象,即使s.vF == f.vF
是False
。
这是一个预期/已知/记录的行为,numpy.vectorize
不能很好地继承,或者我在这里遗漏了一些简单的东西?
(当然,在这种特殊情况下,通过将First.vF
更改为普通的Python方法,或者只是不在super
的构造函数中调用Second
,可以轻松解决问题。)
答案 0 :(得分:2)
这与NumPy无关。这是完全合理的语言设计决策(以及您决定使用该语言的方式)相互作用的结果:
self.F
工作的绑定方法。)结合起来,这些完全合理的行为可能会产生意想不到的行为,如果你不记住细节,而是使用简化的心理模型(例如心理隔离方法和“数据”属性)。详细说明,这在您的示例中发生:
First.__init__
或Second.__init__
,可以立即调用First.__init__
。obj.vF
始终在First.__init__
中为所有obj
创建的矢量化函数。self.F
。对于第二个对象,这是RuntimeError
- 提升Second.F
。你应该在这里使用常规的vF
方法,因为这样可以轻松覆盖子类,因为属性查找的工作方式(参见:MRO)。
答案 1 :(得分:1)
这一般与numpy.vectorize
或numpy
无关......
这里发生的是Second.__init__
调用First.__init__
从vF
创建实例属性(self.F
)(实际上是Second.F
的实例方法包装器1}})并将vF
存储在实例上。现在,当您查找vF
时,您将获得猴子修补版本,而不是原始实例方法Second.vF
。