2013-02-13 67 views
3

在追捕一个不起眼的错误,我无意中发现了一些通过这个小例子,最好的证明:继承numpy.vectorize-ED功能

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.vFf.vF是同一个对象,即使s.vF == f.vFFalse

这是预期/已知/记​​录的行为,并numpy.vectorize不继承发挥很好,还是我失去了一些东西简单吗? (当然,在这种特殊情况下的问题很容易通过更改First.vF正常Python的方法,或者只是没有要求在Second的构造super修复。)

回答

2

这有什么好做NumPy的。这是完全合理的语言设计决策(以及您决定使用该语言的方式)的交互作用的结果:

  • 实例属性优先于类属性。我相信你会同意这是合理的。
  • 方法是类属性,并在此不是特别的。我相信你会同意这是合理的(如果你不这样做,请查看描述符,特别是允许self.F工作的绑定方法)。
  • 继承实例属性附加到同一个对象,而不是一些奇怪的“代理家长”对象或东西。我相信你会同意这是合理的。

这些完全合理的行为相结合,可能会产生意想不到的行为,如果你没有记住细节,而是使用简化的心理模型(例如精神分离方法和“数据”属性)。详细地说,这发生在你的例子中:

  • 相应的构造函数被调用。这既是First.__init__,或Second.__init__这立即调用First.__init__
  • 因此,obj.vF总是First.__init__中为所有obj创建的向量化函数。
  • 但是,每个对象的向量化函数都包含相应对象的self.F。在第二个对象的情况下,这是RuntimeError-提高Second.F

你或许应该只使用常规的方法vF这里,因为这可以很容易压倒一切的子类,由于道路属性查找工作(参见:MRO)。

+0

啊,MRO就是这个词。启发,谢谢! – 2013-02-13 20:30:56

1

这有什么好做numpy.vectorizenumpy一般来说真的...

这是怎么回事是Second.__init__电话First.__init__它创建一个实例属性(vF)出self.F(实际上是围绕Second.F实例方法的包装),并存储为vF的实例。现在,当您查找vF时,您将获得猴子补丁版本,而不是原始实例方法Second.vF