Python: eredità di un attributo di classe (lista)
-
21-09-2019 - |
Domanda
ereditare un attributo di classe da una classe super e poi modificando il valore per la sottoclasse funziona bene:
class Unit(object):
value = 10
class Archer(Unit):
pass
print Unit.value
print Archer.value
Archer.value = 5
print Unit.value
print Archer.value
causa l'emissione:
10
10
10
5
che è solo bene: Archer eredita il valore unitario, ma quando cambio il valore di Archer, il valore di unità rimane intatta.
Ora, se il valore ereditato è una lista, gli scioperi effetto copia superficiale e il valore della superclasse è influenzato anche:
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
5
C'è un modo per "copia completa" un elenco quando eredita dalla classe super-?
Molte grazie
Sano
Soluzione
Non è una questione di superficiale o copie profonde, si tratta di riferimenti e le assegnazioni.
E 'il primo caso Unit.value
e Archer.value
sono due variabili che fanno riferimento allo stesso valore. Quando si esegue Archer.value = 5
, si sta assegnando un nuovo riferimento alla Acher.value.
Per risolvere il problema è necessario assegnare un nuovo valore alla lista Archer.list
.
Se questi valori sono solo andando a essere accessibile da metodi di classe, quindi la soluzione più semplice è quello di fare l'assegnazione quando la classe viene inizializzato.
Altri suggerimenti
La risposta di Michael è bello e semplice, ma se si vuole evitare di dover aggiungere che la linea ad ogni sottoclasse Unit - forse avete un mucchio di altre liste come quella, un metaclasse è un modo semplice per risolvere il 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
uscita:
[10]
[10]
[10]
[5]
È inoltre possibile estendere la stessa idea di trovare automaticamente e copia fino liste (e dicts) definiti 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
Si potrebbe copiare l'elenco nella definizione di Archer:
class Archer(Unit):
listvalue = Unit.listvalue[:]