2012-06-26 18 views
6

Aquí hay un código muy simple que hice para demostrar el problema que estoy encontrando. Lo que sucede aquí es que estoy creando dos instancias diferentes de la misma clase pero cambiar un atributo de uno cambiará el atributo correspondiente de la otra instancia. No estoy seguro de por qué es esto. ¿Es esto normal en Python o me encuentro con algo completamente desordenado?¿Se han sobrescrito varias instancias de una clase al mismo tiempo? (Python)

class exampleClass(object): 

    attribute1=0 
    attribute2="string" 

x=exampleClass 
x.attribute1=20 
x.attribute2="Foo" 

y=exampleClass 
y.attribute1=60 
y.attribute2="Bar" 

print("X attributes: \n") 
print(x.attribute1) 
print(x.attribute2) 

print("Y attributes: \n") 
print(y.attribute1) 
print(y.attribute2) 

Esto es lo que el programa parece que sale de mi consola:

>>> 
X attributes: 

60 
Bar 
Y attributes: 

60 
Bar 
>>> 

Creo que debería decir:

X attributes: 

20 
Foo 
Y attributes: 

60 
Bar 

¿Qué estoy haciendo mal?

+0

Respuesta corta: Tanto 'x' como' y' se refieren al objeto de clase 'exampleClass', no a instancias de este. Para crear instancias, necesita llamar al objeto de clase como en 'x = exampleClass()'. Después, los cambios de atributos que realice a 'x' solo afectarán a la instancia a la que se refiere. – martineau

Respuesta

8

Está creando atributos de clase, cuando quiere atributos de instancia. Utilice:

class exampleClass(object): 
    def __init__(self): 
     self.attribute1 = 0 
     self.attribute2 = "string" 

Además, no se están creando todas las instancias de ExampleClass, necesita esto:

x = exampleClass() 
y = exampleClass() 

Su código es simplemente usando nuevos nombres para la clase, y cambiando sus atributos.

+0

Esto es lo que parece en mi consola ... sigue teniendo el mismo problema. >>> clase exObj (objeto): \t def __init __ (self): \t \t self.attribute1 = 0 \t \t self.attribute2 = "cadena" \t \t >>> ce = exObj > >> ct = exObj >>> ce.attribute1 = 44 >>> ct.attribute1 = 54 >>> ce.attribute1 >>> ct.attribute1 >>> – jecaklafa

+0

lo siento por el áspero formateo – jecaklafa

+0

@jecaklafa: necesita instalar la clase, con parens. –

3

Las modificaciones se han realizado para que quede más claro.

Con el código que tiene, su problema es que las variables xey se refieren a la definición de clase en lugar de crear los objetos que creo han surgido ahora como el problema con todas las discusiones y publicaciones.

x = exampleClass 

Ahora significa que x ahora apunta a la definición de la clase. Es interesante porque desde que han atributo1 como una variable de la ExampleClass, usted puede hacer esto:

x.attribute1 = 3 

Ahora bien, si usted hizo lo siguiente:

exampleClass.attribute1 

lugar de ver a 0 como se establece originalmente, ¡ahora verás 3!

para crear instancias de objetos de la clase que tiene que hacer lo siguiente:

x = exampleClass() 
y = exampleClass() 

Ahora ambas variables hacen referencia a nuevos objetos que cada uno tiene sus propios atributos por lo que si lo hizo:

x.attribute1 = 219 

Entonces encontrará que y.attribute1 no se modifica :) Usar el nombre de la clase y la función es común en python como referencia a la definición. Así que tenga cuidado, si quiere crear una instancia de un objeto, asegúrese de usar paréntesis, si desea llamar a una función, asegúrese de hacerlo también, de lo contrario, usar el nombre es una referencia a la definición.

le sugiero que lea la respuesta de Ned Batchelder, aunque (y otros ahora) que usted debe hacer las variables de instancia de esa manera con función init, ya que es mucho más limpio y más hacia los estándares de diseño que la mayoría siguen.

Pero, en general, como hereda de la clase Object, puede asumir que hacerlo así creará instancias (con los paréntesis) y tal y así puede modificar los valores del objeto ya que creo que deberían ser variables de instancia incluso sin el " yo".

4

Ha realizado los atributos de clase de atributos. Esto significa que tienen un alcance para la clase en sí, no para los objetos de la clase.

Si desea OBJETO DE determinación del alcance que podría hacer algo como:

class exampleClass(object): 
     def __init__(self): 
      self.attribute1=0 
      self.attribute2="string" 

x = exampleClass() 
y = exampleClass() 

Luego, cuando se cambia el valor de atributo de un objeto, que sólo afecta a ese particular, a diferencia de todos los objetos de esa clase.

+2

Aún necesita hacer exampleClass() en lugar de exampleClass, de lo contrario será un puntero a esa clase 'blueprints'. – richardhsu

+0

@richardhsu: Generará un 'NameError' ya que los atributos aún no se habrán creado. –

+1

Exactamente pero aún puede hacer x = exampleClass, es válido en Python y hace que x se refiera a exampleClass entonces sí, su código es correcto para el diseño de la clase, pero crear un objeto de esa clase requiere los paréntesis. – richardhsu

1

Las clases también son objetos en Python. Por lo tanto, pueden asignarse a variables y tener sus propios atributos, al igual que cualquier otro objeto.

Todos los nombres que enlaza en un bloque class se convierten en atributos de la clase que se crea. Son no atributos de las instancias futuras de esa clase. Pero cuando intentas leer un atributo de una instancia y la instancia no tiene ese atributo, Python establece de manera predeterminada los atributos de la clase de la instancia y los devolverá si encuentra uno. Así es como funcionan los métodos en Python; solo son atributos en la clase, y cuando intenta recuperarlos de la instancia (donde no existen) los encuentra al observar la clase.

Teniendo esto en cuenta, su programa no hace lo que cree que hace.

class exampleClass(object): 

    attribute1=0 
    attribute2="string" 

Aquí hemos creado una clase llamada exampleClass, con dos atributos y attribute1attribute2. Son no atributos de instancia; este es un error muy común de las personas que están aprendiendo Python. Necesitas formarte para salir de esto, porque para ejemplos simples, a menudo parece funcionar "como si" fueran atributos de instancia. Los nombres vinculantes en un bloque class crean atributos en el objeto de la clase. La única forma de crear atributos de instancia es obtener una referencia a la instancia una vez que existe y asignarle los atributos; Python le brinda el método __init__ (que se llamará cuando se cree la instancia) como el lugar para hacerlo.

Así que la regla básica es: los nombres definidos en un bloque de clases son atributos en el objeto de clase, los nombres asignados como atributos de self en __init__ son atributos en todas las instancias de esa clase.

Su confusión se agrava aún más por otra cuestión:

x=exampleClass 
x.attribute1=20 
x.attribute2="Foo" 

Dado que las clases son objetos como todo lo demás en Python, este es el código Python perfectamente razonable, pero no hacen lo que usted cree. En realidad, no ha creado una instancia de su clase; para eso necesita llamar a la clase como en exampleClass(). El nombre simple exampleClass simplemente se refiere al objeto de clase en sí, por lo que acaba de vincular el nombre x a ese objeto y luego le asigna algunos de sus atributos. Naturalmente, cuando también enlaza y al objeto de clase y asigna atributos en ese objeto a través de y, el objeto al que se hace referencia en x se ve afectado (es el mismo objeto).

Cuestiones relacionadas