3

あいまいなバグを探しているときに、この最小限の例で最もよく示されているものに出くわしました。

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.vFs.vF == f.vFFalse

これは予想される/既知の/文書化された動作でありnumpy.vectorize、継承とうまく機能しませんか、それともここで簡単なものが欠けていますか?(確かに、この特定のケースではFirst.vF、通常のPythonメソッドに変更するか、コンストラクターを呼び出さないことで、問題を簡単に修正できます。superSecond

4

2 に答える 2

2

これは NumPy とは関係ありません。これは、完全に合理的な言語設計の決定 (および言語の使用方法) の相互作用の結果です。

  • インスタンス属性は、クラス属性よりも優先されます。これが合理的であることにきっと同意していただけると思います。
  • メソッドはクラス属性であり、特別なことではありません。これが合理的であることに同意していただけると確信しています (そうでない場合は、記述子、具体的にはself.F動作を許可するバインドされたメソッドを調べてください)。
  • 継承されたインスタンス属性は、奇妙な「親プロキシ」オブジェクトなどではなく、同じオブジェクトにアタッチされます。これが合理的であることにきっと同意していただけると思います。

これらの完全に合理的な動作が組み合わさると、詳細を念頭に置いておらず、代わりに単純化されたメンタル モデル (たとえば、メソッドと「データ」属性を精神的に分離する) を使用すると、予期しない動作が発生する可能性があります。詳細には、これはあなたの例で起こります:

  • それぞれのコンストラクターが呼び出されます。これはFirst.__init__、 または のいずれかで、Second.__init__すぐに を呼び出しますFirst.__init__
  • したがって、obj.vF常にFirst.__init__for allで作成されたベクトル化された関数ですobj
  • ただし、各オブジェクトのベクトル化された関数self.Fは、それぞれのオブジェクトの をラップします。2 番目のオブジェクトの場合、これはRuntimeError-raisingSecond.Fです。

ここでは通常のvFメソッドを使用する必要があります。これにより、属性ルックアップの仕組みにより、サブクラスによるオーバーライドが容易になるためです (MRO も参照)。

于 2013-02-13T18:00:43.347 に答える
1

これはまったく関係がないnumpy.vectorizenumpy、一般的には...

ここで行われているのは、 (実際には のインスタンス メソッド ラッパーである) からインスタンス属性 ( )を作成し、それをインスタンスとして格納するSecond.__init__呼び出しです。を検索すると、元のインスタンス メソッドではなく、モンキー パッチが適用されたバージョンが表示されます。First.__init__vFself.FSecond.FvFvFSecond.vF

于 2013-02-13T17:58:12.783 に答える