بيثون: ميراث سمة الفصل (قائمة)
-
21-09-2019 - |
سؤال
إن ورث سمة الفصل من فئة سوبر وتغيير قيمة الفئة الفرعية لاحقًا يعمل بشكل جيد:
class Unit(object):
value = 10
class Archer(Unit):
pass
print Unit.value
print Archer.value
Archer.value = 5
print Unit.value
print Archer.value
يؤدي إلى الإخراج:
10
10
10
5
وهو أمر جيد تمامًا: يرث آرتشر القيمة من الوحدة ، لكن عندما أقوم بتغيير قيمة آرتشر ، تظل قيمة الوحدة دون مساس.
الآن ، إذا كانت القيمة الموروثة قائمة ، فإن تأثيرات النسخ الضحلة وتتأثر قيمة الفئة الفائقة أيضًا:
class Unit(object):
listvalue = [10]
class Archer(Unit):
pass
print Unit.listvalue
print Archer.listvalue
Archer.listvalue[0] = 5
print Unit.listvalue
print Archer.listvalue
انتاج:
10
10
5
5
هل هناك طريقة "لنسخ عميق" قائمة عند ورثها من الفئة الفائقة؟
شكرا جزيلا
سانو
المحلول
إنها ليست مسألة نسخ ضحلة أو عميقة ، إنها مسألة مراجع ومهام.
إنها الحالة الأولى Unit.value
و Archer.value
هما المتغيران الذي يشير إلى نفس القيمة. عندما تفعل Archer.value = 5
, ، أنت تقوم بتعيين إشارة جديدة إلى acher.value.
لحل مشكلتك ، تحتاج إلى تعيين قيمة قائمة جديدة إلى Archer.list
.
إذا كانت هذه القيم سيتم الوصول إليها فقط بواسطة طرق الفصل ، فإن أبسط الحلول هو القيام بالمهمة عند تهيئة الفئة.
نصائح أخرى
إجابة مايكل لطيفة وبسيطة ، ولكن إذا كنت ترغب في تجنب الاضطرار إلى إضافة هذا الخط إلى كل فئة فرعية للوحدة - ربما يكون لديك مجموعة من القوائم الأخرى مثل تلك ، فإن metaclass هي وسيلة سهلة لحل المشكلة
class UnitMeta(type):
def __init__(self, *args):
super(UnitMeta, self).__init__(*args)
self.listvalue = [10]
class Unit(object):
__metaclass__ = UnitMeta
pass
class Archer(Unit):
pass
print Unit.listvalue
print Archer.listvalue
Archer.listvalue[0] = 5
print Unit.listvalue
print Archer.listvalue
انتاج:
[10]
[10]
[10]
[5]
يمكنك أيضًا تمديد هذه الفكرة نفسها للعثور تلقائيًا ونسخ القوائم (والديكتات) المحددة في الوحدة
class UnitMeta(type):
def __init__(self, *args):
super(UnitMeta, self).__init__(*args)
for superclass in self.__mro__:
for k,v in vars(superclass).items():
if isinstance(v, (list, dict, )):
setattr(self, k, type(v)(v))
class Unit(object):
__metaclass__ = UnitMeta
listvalue = [10]
class Archer(Unit):
pass
يمكنك نسخ القائمة في تعريف Archer:
class Archer(Unit):
listvalue = Unit.listvalue[:]