2013-02-13 74 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