1

2 番目のクラスで 2 回インスタンス化するカスタム クラスがあります。

[編集: 古いコードは私の問題を正確に捉えていませんでした。より明確にするために書き直しています。Foo はコールバック関数を使用してネットワーク イベントを処理します (複数の接続が必要なため、Bar には複数の Foo フィールドがあり、単に継承することはできません)。Bar クラスでは、コールバックを上書きして別のことをしたいと考えています。Foo で callb を書き換えても機能しません。他のインスタンスで継承しているためです]

class Foo(object):
    def __init__(self, x):
        self._x = x
        #When an event happens, call callb()
        self.on_certain_event(callback=callb)

    def callb(self):
        print self._x

    def run(self):
        waitForEventsInfinitely() #

class Bar(object):
    def __init__(self):
        self._foo = Foo(5)
        #OVERWRITE THE EXISTING CALLBACK METHOD IN THE Foo CLASS!
        self._foo.callb = self.callb

    def callb(self):
        print self._x * 10

    def run(self):
        waitForEventsInfinitely() # Not going to actually write t

f = Foo(2)
f.run()
b = Bar()
b.run()

[Foo で run() を呼び出すと、正しく動作します。ただし、Bar から Foo の callb メソッドを上書きすることはできません - Foo によって参照されるはずの self._x が Bar から呼び出されようとしています]

ただし、コードを実行すると、期待値 50 ではなく、「Bar には属性 '_x' がありません」というエラーが表示されます。明らかに、Bar のテストの自己は、実際にメソッドを呼び出している Foo ではなく、依然として Bar を参照しています。 . Bar の内部 Foo self._foo フィールドであると予想していました。

私の問題は名前マングリングと関係があると思われますが、メソッドが上書きされた自分自身のフィールドがある場合、説明的なソースを見つけることができませんでした。ほとんどの例は、別のクラスから継承しているときのようです。

4

3 に答える 3

1

Python のクラスがどのように機能するかについての簡単なレッスン: クラス オブジェクト (「メソッド」) に格納されている関数はすべて、使用したクラスまたはインスタンスにメソッドをバインドする記述子(オブジェクトから属性を取得する方法を説明する) によって自動的にフェッチされます。それを得るために。

例えば:

Foo.test 

クラス Fooのバインドされていないメソッドです: これはFoo、クラス オブジェクトからフェッチされたことを認識している記述子によって作成されたオブジェクトです。

Foo().test 

クラス Foo のインスタンスのバインドされたメソッドです。このメソッドはFoo、関数のフェッチに使用される のインスタンスを格納します。このインスタンスは、結果のオブジェクトを呼び出すときに最初の引数として自動的に渡されるselfため、メソッドを定義するときに最初のパラメーターとして記述します。

だから、あなたがやろうとしていることはこれです:

  1. クラスから生の関数を取得します(記述子を介さずに)testBar
  2. この関数をインスタンスにバインドしますFoo
  3. この関数を foo インスタンスに保存します

だから、これはあなたがそれを行う方法です:

import types 

class Bar(object):
    def __init__(self):
        self._foo = Foo(5)

        raw_function = Bar.test_Bar.__func__                        # 1)
        bound_to_foo = types.MethodType(raw_function, self._foo)    # 2)    
        self._foo.test = bound_to_foo                               # 3)

    def test(self):
        print self._x * 10

記述子の詳細については、この質問を参照してください。

于 2013-04-08T22:49:11.160 に答える
0

コードを見ると、b.test を呼び出すときに、Bar のインスタンスでメソッドを直接呼び出しています。Foo のインスタンスはまったく言及されていません。b には _x という名前のメンバーがないため、エラーが発生します。期待どおりの動作を得るには、b._foo.test を呼び出す必要があります。これにより、期待される 50 の結果が得られます。

b.test を直接呼び出せるようにしたい場合は、self._x を self._foo._x に変更します。この方法では、_foo のメソッドを変更する必要はありません。とにかく継承を使用できるのに、オブジェクトに異なるメソッドを割り当てる理由がよくわかりません。

于 2013-04-08T22:20:44.050 に答える