Python: La herencia de un atributo de clase (lista)
-
21-09-2019 - |
Pregunta
heredar un atributo de clase de una superclase y luego cambiando el valor de la subclase funciona bien:
class Unit(object):
value = 10
class Archer(Unit):
pass
print Unit.value
print Archer.value
Archer.value = 5
print Unit.value
print Archer.value
conduce a la salida:
10
10
10
5
Lo que está bien: Archer hereda el valor de la Unidad, pero cuando cambio el valor de Archer, el valor de unidad permanece intacta.
Ahora, si el valor heredado es una lista, los ataques de efecto copia superficial y el valor de la superclase también se ve afectada:
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
Salida:
10
10
5
5
¿Hay una manera de "copia en profundidad" una lista cuando heredarlo de la superclase?
Muchas gracias
Sano
Solución
No es una cuestión de poca profundidad o copias profundas, es una cuestión de referencias y asignaciones.
Es la primera Unit.value
caso y Archer.value
son dos variables que hacen referencia al mismo valor. Cuando lo haga Archer.value = 5
, está asignando una nueva referencia a Acher.value.
Para resolver el problema es necesario asignar un nuevo valor a la lista de Archer.list
.
Si estos valores sólo van a ser visitada por métodos de clase, a continuación, la solución más simple es hacer la asignación cuando se inicializa la clase.
Otros consejos
La respuesta de Michael es agradable y simple, pero si usted desea evitar tener que añadir esa línea para cada subclase Unidad - tal vez usted tiene un montón de otras listas como esa, una metaclase es una manera fácil de resolver el problema
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
salida:
[10]
[10]
[10]
[5]
También puede extender esta misma idea de encontrar automáticamente y copiar las listas (y predice) definidas en la unidad
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
Se puede copiar la lista en la definición de Archer:
class Archer(Unit):
listvalue = Unit.listvalue[:]