بيثون: جيل فئة ديناميكية: أعضاء الكتابة فوق
-
22-09-2019 - |
سؤال
لديّ تسلسل هرمي من فئة 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" مثل فئة الفئة!؟
هل يمكن لأي شخص أن يكون لطيفًا وشرح لي ، ما سبب هذا؟ شكرا لك مقدما!
المحلول
Phild ، كما تعلمون ، عند بادئة اسم السمة مع inderscore مزدوج __
, ، مترجم Python التغييرات تلقائيًا (MANGLES) اسم السمة من __attribute
ل _CLS__attribute
, ، حيث CLS هو اسم الفصل.
ومع ذلك ، عندما تقول
return type(name, (cls, ), { '__dict' : {} })
المفاتيح في القاموس { '__dict' : {} }
لا تحصل على مشوهة. __dict
بقي على حاله.
وهكذا ينتهي الأمر مع كليهما 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__dict
يشير إلى سمة فئة C. لذلك عند الركض
C.setval(1, 5)
أنت تتغير D._C__dict
إلى جانب C._C__dict
. فهي واحدة ونفس الشيء.
نصائح أخرى
هنا الفصل في الوثائق حول سمات "الخاصة". وعلقت على تعريف الفصل لجعله أكثر وضوحًا:
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
سمة ، ولكن يتم استخدام واحد فقط من الفئة الأساسية.
لا تنطبق مفاهيم Java أو C ++ لـ "محمية" و "خاصة". يقوم Python بتسمية Python قليلاً ، ولكن ليس ما تتخيله.
ال __name
هل بعض الأسماء يتدحرج ، مما يجعل من الصعب الوصول لأن الاسم محجب.
لك _dict
و __dict
هي ببساطة سمات على مستوى الفصل والتي تتقاسمها ببساطة جميع حالات الفصول.