Básicamente el título Aquí hay una clase de código de muestra myClass (): def __init __ (self, variable): self.variable = variable def set (self, variable): self.variable = variable def get (self): ...

0
Zuj3brusu 14 mar. 2021 a las 17:43

3 respuestas

La mejor respuesta

El problema es que los diccionarios son mutables, lo que significa que sus valores internos pueden cambiar. Como resultado, cuando dices

x = {"a" : 1}
y = x 

Ambos valores x y y apuntan al mismo diccionario.

Solución A: copiando la variable dentro del constructor

Una solución es

class myClass():
    def __init__(self,variable):
        self.variable=variable.copy() # create a copy of the dictionary
    def set(self,variable):
        self.variable=variable
    def get(self):
        print(self.variable)

l=[]

x={'a':1}
for i in range(3):
    t=myClass(x)
    x['a']+=1
    l.append(t)

for t in l:
    t.get()   

Aquí creamos una copia superficial del diccionario. Ahora bien, esta no es la mejor práctica, porque muchos tipos no implementan copy, por lo que encontrará errores si no está utilizando un diccionario como variable.

Solución A con Try-Except

También podríamos implementar lo siguiente:

class myClass():
    def __init__(self,variable):
        try: 
            self.variable=variable.copy()
        except AttributeError:
            self.variable = variable
    def set(self,variable):
        self.variable=variable
    def get(self):
        print(self.variable)

Aquí, hacemos copias superficiales cada vez que una variable es mutable y, de lo contrario, simplemente asignamos el valor.

Solución B

Otra solución es simplemente copiar los diccionarios fuera de la clase por completo

l=[]

x={'a':1}
for i in range(3):
    t=myClass(x)
    x = x.copy() # copy the dictionary after passing it 
    x["a"] += 1 
    l.append(t)

for t in l:
    t.get()    

Copias superficiales

Como acotación al margen, probemos mi solución, pero usemos x={'a':{"b" : 1 }} e incrementemos x["a"]["b"]:

class myClass():
    def __init__(self,variable):
        self.variable=variable
    def set(self,variable):
        self.variable=variable
    def get(self):
        print(self.variable)

l=[]

x={'a':{"b" : 1 }}
for i in range(3):
    t=myClass(x)
    x = x.copy()
    x["a"]["b"] += 1 
    l.append(t)

for t in l:
    t.get()    

Aquí, la salida es

{'a': {'b': 4}}
{'a': {'b': 4}}
{'a': {'b': 4}}

Esto se debe a que copy realiza una copia superficial , que copia cada una de las referencias en x en un nuevo diccionario. Como resultado, el diccionario resultante contendrá entradas con las mismas referencias exactas que en el diccionario original. Cuando tienes un número entero, escribir x["a"] += 1 sombrea la referencia anterior, pero por supuesto mutar el diccionario b no implica sombrear, y obtenemos el resultado anterior.

0
Kraigolas 14 mar. 2021 a las 15:04

Estás apuntando ax desde diferentes objetos. x tiene su propia declaración y python entiende x como índice para sus objetos.

>>> l = []
>>> 
>>> for i in range(3):
...     t=myClass({'a': 1 + i})
...     l.append(t)
... 
>>> for t in l:
...     t.get()
... 
{'a': 1}
{'a': 2}
{'a': 3}
1
Vahram Danielyan 14 mar. 2021 a las 14:50

Cada instancia de la clase hace referencia al mismo diccionario. Las variables en Python no contienen objetos, tienen una referencia (también conocida como puntero) a la ubicación de un objeto.

Entonces, cada una de las instancias tiene un puntero al mismo objeto. Dado que ese objeto (un diccionario) es mutable, cuando lo cambie, permanecerá en el mismo lugar. Por lo tanto, todas las instancias tendrán la misma actualización.

Querrá hacer una copia (ya sea superficial o profunda) para tener el comportamiento que espera.

Como nota al margen, las funciones get y set de la clase son algo inútiles. Sabes que puedes acceder al atributo directamente.

1
user1558604 14 mar. 2021 a las 14:50