继承numpy.vectorize-ed函数

时间:2013-02-13 17:53:38

标签: python numpy

在寻找一个不起眼的错误时,我偶然发现了这个最小例子最好的证明:

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方法,或者只是不在super的构造函数中调用Second,可以轻松解决问题。)

2 个答案:

答案 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.vectorizenumpy无关......

这里发生的是Second.__init__调用First.__init__vF创建实例属性(self.F)(实际上是Second.F的实例方法包装器1}})并将vF存储在实例上。现在,当您查找vF时,您将获得猴子修补版本,而不是原始实例方法Second.vF