Recientemente he combatido un error en Python. Era uno de esos bichos novatos tontos, pero me hizo pensar sobre los mecanismos de Python (soy un programador de C++ desde hace mucho tiempo, nuevo para Python). Voy a diseñar el código de error y explicar lo que hice para solucionarlo, y luego tengo un par de preguntas ...Inicialización de miembros de la clase de Python
El escenario: Tengo una clase llamada A, que tiene un miembro de datos del diccionario, lo siguiente es su código (esto es una simplificación, por supuesto):
class A:
dict1={}
def add_stuff_to_1(self, k, v):
self.dict1[k]=v
def print_stuff(self):
print(self.dict1)
La clase utilizando este código es la clase B:
class B:
def do_something_with_a1(self):
a_instance = A()
a_instance.print_stuff()
a_instance.add_stuff_to_1('a', 1)
a_instance.add_stuff_to_1('b', 2)
a_instance.print_stuff()
def do_something_with_a2(self):
a_instance = A()
a_instance.print_stuff()
a_instance.add_stuff_to_1('c', 1)
a_instance.add_stuff_to_1('d', 2)
a_instance.print_stuff()
def do_something_with_a3(self):
a_instance = A()
a_instance.print_stuff()
a_instance.add_stuff_to_1('e', 1)
a_instance.add_stuff_to_1('f', 2)
a_instance.print_stuff()
def __init__(self):
self.do_something_with_a1()
print("---")
self.do_something_with_a2()
print("---")
self.do_something_with_a3()
en cuenta que cada llamada a do_something_with_aX()
inicializa una nueva instancia "limpia" de la clase a, e imprime el diccionario antes y después de la adición.
El error (en caso de que no se ha descubierto todavía):
>>> b_instance = B()
{}
{'a': 1, 'b': 2}
---
{'a': 1, 'b': 2}
{'a': 1, 'c': 1, 'b': 2, 'd': 2}
---
{'a': 1, 'c': 1, 'b': 2, 'd': 2}
{'a': 1, 'c': 1, 'b': 2, 'e': 1, 'd': 2, 'f': 2}
En la segunda inicialización de la clase A, los diccionarios no están vacíos, pero comienzan con el contenido de la última inicialización, Etcétera. Esperaba que comenzaran "frescos".
Lo que resuelve este "error" es, obviamente, añadiendo:
self.dict1 = {}
En el __init__
constructor de la clase A. Sin embargo, lo que me hizo preguntarme:
- ¿Cuál es el significado de la "dict1 = {} "inicialización en el punto de la declaración de dict1 (primera línea en la clase A)? No tiene sentido?
- ¿Cuál es el mecanismo de creación de instancias que causa la copia de la referencia de la última inicialización?
- Si agrego "self.dict1 = {}" en el constructor (o cualquier otro miembro de datos), ¿cómo no afecta el miembro del diccionario de las instancias previamente inicializadas?
EDIT: Después de las respuestas ahora entiendo que al declarar un miembro de datos y no se hace referencia a ella en el __init__
o en otro lugar como self.dict1, estoy prácticamente la definición de lo que se llama en C++/Java un miembro de datos estáticos. Al llamarlo self.dict1 lo estoy haciendo "vinculado a instancia".
Debe usar clases de estilo nuevo, derivar del objeto. – nikow