Питон:Наследование атрибута класса (списка)
-
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
что просто отлично:Archer наследует значение Unit, но когда я меняю значение Archer, значение Unit остается нетронутым.
Теперь, если унаследованное значение представляет собой список, срабатывает эффект поверхностного копирования, и это также влияет на значение суперкласса:
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
.
Если доступ к этим значениям будет осуществляться только методами класса, то самым простым решением будет выполнение присваивания при инициализации класса.
Другие советы
Ответ Майкла хорош и прост, но если вы хотите избежать необходимости добавлять эту строку в каждый подкласс Unit - возможно, у вас есть куча других списков, подобных этому, метакласс - простой способ решить проблему.
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]
Вы также можете расширить эту идею, чтобы автоматически находить и копировать списки (и словари), определенные в 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
Вы можете скопировать список из определения Арчера:
class Archer(Unit):
listvalue = Unit.listvalue[:]