Python: Inheritance of a class attribute (list)
inheriting a class attribute from a super class and later changing the value for the subclass works fine:
class Unit(object):
value = 10
class Archer(Unit):
pass
print Unit.value
print Archer.value
Archer.value = 5
print Unit.value
print Archer.value
leads to the output:
10 10 10 5 which is jus开发者_开发问答t fine: Archer inherits the value from Unit, but when I change Archer's value, Unit's value remains untouched.Now, if the inherited value is a list, the shallow copy effect strikes and the value of the superclass is also affected:
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
Output:
10 10 5 5Is there a way to "deep copy" a list when inheriting it from the super class?
Many thanks
SanoIt is not a matter of shallow or deep copies, it is a matter of references and assignments.
It the first case Unit.value
and Archer.value
are two variables which reference the same value. When you do Archer.value = 5
, you are assigning a new reference to Acher.value.
To solve your problem you need to assign a new list value to the Archer.list
.
If these values are only going to be accessed by class methods, then the simplest solution is to do the assignment when the class is initialized.
Michael's answer is nice and simple, but if you wish to avoid having to add that line to each Unit subclass - maybe you have a bunch of other lists like that one, a metaclass is an easy way to solve the problem
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
output:
[10]
[10]
[10]
[5]
You can also extend this same idea to automatically find and copy up lists (and dicts) defined in Unit
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
You coud copy the list in the definition of Archer:
class Archer(Unit):
listvalue = Unit.listvalue[:]
精彩评论