2012-01-02 16 views
26

Tengo un problema para entender cómo funcionan las variables clase/instancia en python. No entiendo por qué cuando intento este código la variable de lista parece ser una variable de clasevariables de instancia de clase python y variables de clase

class testClass(): 
    list = [] 
    def __init__(self): 
     self.list.append('thing') 

p = testClass() 
print p.list 

f = testClass() 
print f.list 

de salida:

['thing'] 
['thing', 'thing'] 

y cuando hago esto parece ser una variable de instancia

class testClass(): 
    def __init__(self): 
     self.list = [] 
     self.list.append('thing') 

p = testClass() 
print p.list 

f = testClass() 
print f.list 

de salida:

['thing'] 
['thing'] 

muchas gracias

jon

+1

Si entiendo correctamente, usted está solicitando la razón de ser de una decisión de diseño particular con respecto a la sintaxis de Python. Para tales preguntas, la mejor respuesta es "porque encaja con el espíritu del lenguaje", o más descaradamente: "pregúntele a su creador". – Xion

+0

ok así que las variables son variables de clase por defecto, de ahí surgió mi confusión, esa debería haber sido mi pregunta, las variables por defecto son las variables de clase –

+4

@jonathantopf No, las variables NO son variables de clase por defecto. En Python no declaras varables. En realidad, en realidad no son variables (python es un _variable_language), solo nombres. Y no declaras ni asientes nombres, los vinculas a un objeto. Y cada objeto en el tiempo de ejecución tiene un diccionario de nombres a objetos. E incluso si dos objetos son de la misma clase, pueden tener diccionarios muy diferentes. – rodrigo

Respuesta

40

Esto es debido a la forma de Python resuelve los nombres con el .. Cuando escribe self.list, el tiempo de ejecución de Python intenta resolver el nombre list buscándolo primero en el objeto instancia, y si no se encuentra en la instancia de la clase.

Veamos en ella paso a paso

self.list.append(1) 
  1. ¿Hay un nombre list en el objeto self?
    • Sí: ¡Utilícela! Terminar.
    • No: Ir a 2.
  2. ¿Hay un nombre list en la instancia de clase de objeto self?
    • Sí: ¡Utilícela! Terminar
    • No: ¡Error!

Pero cuando se enlaza un nombre de las cosas son diferentes:

self.list = [] 
  1. ¿Hay un nombre list en el objeto self?
    • Sí: ¡Sobrescríbelo!
    • No: ¡Enlazar!

Por lo tanto, es siempre una variable de instancia.

Su primer ejemplo crea un list en la instancia de la clase, ya que este es el ámbito activo en ese momento (no self en ninguna parte). Pero su segundo ejemplo crea un list explícitamente en el alcance de self.

Más interesante sería el ejemplo:

class testClass(): 
    list = ['foo'] 
    def __init__(self): 
     self.list = [] 
     self.list.append('thing') 

x = testClass() 
print x.list 
print testClass.list 
del x.list 
print x.list 

que imprimirá:

['thing'] 
['foo'] 
['foo'] 

En el momento de eliminar el nombre de la instancia el nombre de clase es visible a través de la referencia self.

+0

ok im following, en ese caso hay una manera de definir variables de instancia fuera de la función __init__, intenté hacer 'self.list []' fuera de __init__, esto tiene sentido, pero ¿hay alguna manera? –

+0

@jonathantopf: las variables de instancia solo se pueden crear cuando tienes una instancia. Deben crearse en un método que se llama en una instancia. Su otra opción es sobrecargar '__new__' y crearlos allí, pero eso es realmente feo, ya que no es para lo que' __new__' es realmente, y en realidad no es mejor que crearlos en '__init__'. ¿Qué, orar, contar, crees que necesitas esta habilidad? Podrías crear una metaclase que sobrecargue '__new__' para ver el dict de la clase y copiar cosas al dict de instancia. Pero eso es ** realmente ** feo. – Omnifarious

+0

:) punto tomado, eso tiene sentido, odio hacer preguntas como esa pero a veces es la mejor manera de averiguar si lo que estoy pensando es una locura o no, ¡ahora lo sé! –

0

Al crear una instancia de una clase, el método __init__ se ejecuta automáticamente.

En el primer caso, su lista es un atributo de clase y la comparten todas sus instancias. Se obtuvieron dos 'cosas' porque se agregó una cuando se instaló instantáneamente p y otra cuando se instanciaron f (la primera ya se agregó a la primera llamada).

3

En su primer ejemplo, list es un atributo de la clase, compartido por todas las instancias de la misma. Esto significa que incluso se puede acceder a ella sin tener un objeto de tipo testClass:

>>> class testClass(): 
...  list = [] 
...  def __init__(self): 
...    self.list.append("thing") 
... 
>>> testClass.list 
[] 
>>> testClass.list.append(1) 
>>> testClass.list 
[1] 

Pero todos los objetos comparten el atributo list con la clase y entre sí:

>>> testObject = testClass() 
>>> testObject.list 
[1, 'thing'] 
>>> testClass.list 
[1, 'thing'] 
>>> 
>>> testObject2 = testClass() 
>>> testClass.list 
[1, 'thing', 'thing'] 
>>> testObject2.list 
[1, 'thing', 'thing'] 
4

Python tiene reglas interesantes sobre mirar nombres Si realmente quiere doblar su mente, probar este código:

class testClass(): 
    l = [] 
    def __init__(self): 
     self.l = ['fred'] 

Esto le dará a cada instancia de una variable llamada l que enmascara la clase variable de l. Aún podrá obtener la variable de clase si lo hace self.__class__.l.

La forma en que pienso es esto ... Siempre que lo haga instance.variable (incluso para los nombres de los métodos, son simplemente variables cuyos valores son funciones) lo busca en el diccionario de la instancia. Y si no puede encontrarlo allí, intenta buscarlo en el diccionario de la clase de la instancia. Esto es solo si la variable está siendo 'leída'. Si se le asigna, siempre crea una nueva entrada en el diccionario de instancia.

+0

¡Qué complicaciones tortuosas! Esta respuesta fue realmente útil, porque el caso de "leer versus escribir" me causaba dolor de cabeza. – dotslash

Cuestiones relacionadas