4

実行時に拡張したいpythonクラス階層があります。さらに、この階層のすべてのクラスには、すべてのサブクラスで上書きしたい静的属性「dict」があります。簡単に言うと、次のようになります。

'dict' は保護された (公開されていますが、先頭にアンダースコアが付いている) メンバーです

class A(object):
    _dict = {}

    @classmethod
    def getdict(cls):
        return cls._dict

    @classmethod
    def setval(cls, name, val):
        cls._dict[name] = val

    @classmethod
    def addchild(cls, name):
        return type(name, (cls, ), { '_dict' : {} })

B = A.addchild('B')
A.setval(1, 5)

print A.getdict()
# prints: {1: 5}
# like expected

print B.getdict()
# prints: {}
# like expected

これは期待どおりに機能します。問題は、次のとおりです。属性をプライベートに宣言すると、なぜ機能しなくなるのですか。

プライベートメンバーである「dict」と同じこと

class C(object):
    __dict = {}

    @classmethod
    def getdict(cls):
        return cls.__dict

    @classmethod
    def setval(cls, name, val):
        cls.__dict[name] = val

    @classmethod
    def addchild(cls, name):
        return type(name, (cls, ), { '__dict' : {} })

D = C.addchild('D')
C.setval(1, 5)

print C.getdict()
# prints: {1: 5}
# like expected

print D.getdict()
# prints: {1: 5}
# why!?

突然D、 のサブクラスのC'dict' の値がそのスーパークラスと同じになる!?

誰か親切に説明してくれませんか、これの理由は何ですか?前もって感謝します!

4

3 に答える 3

3

ご存知のように、属性名の前に 2 つのアンダースコアを付けると__、python インタープリターは自動的に属性名を から に変更 (マングル)__attributeします_CLS__attribute。ここで、CLS はクラス名です。

しかし、あなたが言うとき

return type(name, (cls, ), { '__dict' : {} })

ディクショナリのキーは{ '__dict' : {} }壊れません。__dict同じまま。

したがって、 D は と の両方D._C__dictになりD.__dictます。

(Pdb) dir(D)
['_C__dict', '__class__', '__delattr__', '__dict', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'addchild', 'getdict', 'setval']

D._C__dictC のクラス属性を参照します。だからあなたが走るとき

C.setval(1, 5)

あなたも変化D._C__dictしていC._C__dictます。それらは同一のものです。

于 2009-11-24T19:12:33.517 に答える
2

これは、「プライベート」属性に関するドキュメントの章です。そして、より明確にするためにクラス定義にコメントしました:

class C(object):
    __dict = {} # This creates C.__dict__['_C__dict']

    @classmethod
    def getdict(cls):
        return cls.__dict # Uses cls.__dict__['_C__dict'] 

    @classmethod
    def setval(cls, name, val):
        cls.__dict[name] = val # Uses cls.__dict__['_C__dict'] 

    @classmethod
    def addchild(cls, name):
        return type(name, (cls, ), { '__dict' : {} }) # Creates child.__dict__['__dict']

つまり、すべての子には独自の__dict属性がありますが、基本クラスの 1 つだけが使用されます。

于 2009-11-24T18:57:21.533 に答える
1

Java または C++ の「保護」および「プライベート」の概念は適用されません。Python の命名規則は少しだけですが、あなたが想像しているようなものではありません。

__nameいくつかの名前マングリングを行い、名前が不明瞭になるためアクセスが困難になります。

あなたの_dictand__dictは、クラスのすべてのインスタンスによって単純に共有されるクラスレベルの属性です。

于 2009-11-24T18:54:07.627 に答える