Python: clases derivadas acceden al diccionario de la clase base en la misma ubicación de memoria

Me pregunto por qué un diccionario, que se define en una clase base y se accede desde clases derivadas, obviamente está presente solo en una ubicación de memoria. Un breve ejemplo:

class BaseClass: _testdict = dict() _testint = 0 def add_dict_entry(self): self._testdict["first"] = 1 def increment(self): self._testint += 1 class Class1(BaseClass): pass class Class2(BaseClass): pass object1 = Class1() object2 = Class2() object1.add_dict_entry() object1.increment() print(object2._testdict) print(object2._testint) 

y la salida es:

 {'first': 1} 0 

¿Por qué una llamada al “add_dict_entry” de object1 afecta el diccionario de object2? Usando enteros (“incremento”) la variable de clase base no se ve afectada.

Muchas gracias.

Lorenz

Es porque _testdict es una variable de clase: se define solo una vez, cuando la clase se construye inicialmente. Si desea que sea separado para cada instancia, conviértalo en una variable de instancia:

 class BaseClass: _testint = 0 def __init__(self): self._testdict = dict() def add_dict_entry(self): self._testdict["first"] = 1 

(Tenga en cuenta que también tendría que crear métodos __init__ para Class1 y Class2 , los cuales tendrían que llamar BaseClass.__init__(self) ).

_testint comporta de manera diferente porque estás realizando una operación de reenlazado en lugar de una operación de mutación. Los ints son inmutables, por lo que no se puede “cambiar” uno self._testint += 1 es solo azúcar sintáctica para self._testint = self._testint + 1 . De manera similar, puede realizar una operación de self._testdict en self._testdict que no se compartirá entre instancias; por ejemplo, self._testdict = {} se restablecerá solo el _testdict esa instancia.

En python, int es inmutable, por lo tanto, la operación + = rebotará la variable de clase en una variable de instancia. Por otro lado, un índice de diccionario muta el diccionario en su lugar. Un ejemplo más comparable sería

 def add_dict_entry(self): # create a new dict tmp = dict(self._testdict) tmp["first"] = 1 # shadow the class variable with an instance variables self._testdict = tmp