Python: dynamische Klasse Generation: Überschreiben Mitglieder
-
22-09-2019 - |
Frage
ich eine Python-Klassenhierarchie habe, dass ich zur Laufzeit verlängern will. Außerdem hat jede Klasse in dieser Hierarchie ein statisches Attribut ‚dict‘, dass ich in jeder Unterklasse überschrieben werden soll. Fachter es sieht wie folgt aus:
'dict' eine geschützte (Öffentlichkeit, sondern mit führendem Unterstrich) Mitglied
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
Dies funktioniert genauso wie erwartet. Die Frage ist nun: Warum tut es nicht mehr funktionieren, wenn ich das Attribut privat deklarieren:
Nun ist die gleiche Sache mit 'dict' ein privates Mitglied beeing
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!?
Plötzlich D
, die Unterklasse von C
, hat die gleichen Werte in 'dict' als Superklasse!?
Könnte jemand so freundlich sein und mir erklären, was der Grund dafür ist? Vielen Dank im Voraus!
Lösung
phild, wie Sie wissen, wenn Sie einen Attributnamen mit Doppelstrich __
Präfix, automagically das Python-Interpreter ändert (Mangeln) Attributnamen von __attribute
zu _CLS__attribute
, wo CLS ist der Klassenname.
Wenn Sie jedoch sagen
return type(name, (cls, ), { '__dict' : {} })
die Schlüssel im Wörterbuch { '__dict' : {} }
verstümmelt werden nicht. __dict
bleibt gleich.
So D endet mit beiden D._C__dict
und D.__dict
oben:
(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__dict
bezieht sich auf C Klasse Attribut. Also, wenn Sie laufen
C.setval(1, 5)
Sie ändern D._C__dict
sowie C._C__dict
. Sie sind ein und dasselbe.
Andere Tipps
Hier ist ein Kapitel in der Dokumentation über "private" Attribute . Und ich bemerkte man Klassendefinition, um es klar:
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']
d. alle Childs haben ihr eigenes __dict
Attribut, aber nur einer von Basisklasse verwendet wird.
Die Java oder C ++ Konzepte von „geschützt“ und „privaten“ nicht gelten. Die Namenskonvention Python tut ein wenig, aber nicht das, was bildest du dir.
Der __name
hat einige Namen Mangeln, ist es schwer, den Zugang zu machen, weil der Name verdeckt wird.
Ihre _dict
und __dict
sind einfach Klasse-Level-Attribute, die von allen Instanzen der Klassen einfach geteilt werden.