5

私は次のようなPythonのテストコードを書きます。

class Parent(object):
    @classmethod
    def dispatch(klass):
        print 'klass = %s' % klass
        return klass().__dispatch()
    def __dispatch(self):
        print 'This Parent.__dispatch()'
        print self


class Child(Parent):
    def __dispatch(self):
        print 'This Child.__dispatch()'
        print self


if __name__=='__main__':
    print 'Calling Parent.dispatch() ...\n'
    Parent.dispatch()
    print ''
    print 'Calling Child.dispatch() ...\n'
    Child.dispatch()
    print '\n-END'

そして、出力は次のとおりです。

 Calling Parent.dispatch() ...

 klass = <class '__main__.Parent'> 
 This Parent.__dispatch()
 <__main__.Parent object at 0x0000000002D3A2E8>

 Calling Child.dispatch() ...

 klass = <class '__main__.Child'> 
 This Parent.__dispatch()
 <__main__.Child object at 0x0000000002D3A2E8>

 -END

Childクラスの上書きされたメソッド'__dispatch(self)'が呼び出されなかったのは非常に奇妙です。

誰かがこれについて説明できますか?

ありがとうございました。

4

2 に答える 2

7

2 つのアンダースコアで始まるメソッド名は、自動的にマングルされます。内部的には、文字列_ClassNameがメソッド名の前に追加されます。

>>> class Foo(object):
...     def __bar(self):
...         pass
... 
>>> Foo.__dict__.keys()
['__dict__', '__module__', '__weakref__', '__doc__', '_Foo__bar']

この名前変更は、クラス内の他のメソッドでこのメソッド名を参照するものに対しても行われます。

したがって、__dispatch()メソッドの名前が に変更され_Parent__dispatch()dispatch()メソッドは代わりに呼び出すように変更さself._Parent__dispatch()れます。同様に、Childクラスには_Child__dispatch()メソッドがあるため、そのスーパークラスのメソッドをオーバーライドしません_Parent__dispatch()

これが、目に見える結果を見る理由です。__dispatch()メソッドの名前を_dispatch()(アンダースコア 1 つだけ) に変更すると、期待どおりに機能します。

なぜpythonはこれを行うのですか?これは、プライベート属性とメソッドを提供する形式であり、それらを継承するクラスによって誤ってオーバーライドされることはありません。Python エクスプレッション リファレンスのプライベート ネーム マングリングを参照してください。

PEP 8 Python Style Guideには、プライベート名マングリングについて次のように書かれています。

クラスがサブクラス化されることを意図しており、サブクラスで使用したくない属性がある場合は、先頭にアンダースコアを 2 つ付け、末尾にアンダースコアを付けない名前を付けることを検討してください。これにより、Python の名前マングリング アルゴリズムが呼び出され、クラスの名前が属性名にマングルされます。これにより、サブクラスに誤って同じ名前の属性が含まれている場合に、属性名の衝突を回避できます。

注 1: マングルされた名前では単純なクラス名のみが使用されることに注意してください。そのため、サブクラスが同じクラス名と属性名の両方を選択した場合でも、名前の衝突が発生する可能性があります。

__getattr__()注 2: 名前マングリングは、デバッグや利便性の低下など、特定の用途に使用できます 。ただし、名前マングリング アルゴリズムは十分に文書化されており、手動で簡単に実行できます。

注 3: 誰もが名前マングリングを好むわけではありません。偶発的な名前の衝突を避ける必要性と、高度な発信者が使用する可能性とのバランスを取るようにしてください。

于 2012-09-15T14:03:10.390 に答える
1

__dispatch の代わりに _dispatch メソッドを呼び出してみましたか?

ポイントは、__dispatch が内部的に _NameOfTheClass_dispatch (または一種の「プライベート」メンバー関数の動作を与えるようなもの) に変換されることです。これが、オーバーライドが失敗する理由です。

_dispatch を使用すると、メンバー関数の名前はアンダースコアの影響を受けず、プログラムは希望どおりに動作します。

于 2012-09-15T14:03:05.710 に答える