2010-03-08 6 views
5

Suponga que tiene algo como esto:Instancias y atributos de Python: ¿es esto un error o lo entendí por completo?

class intlist: 
     def __init__(self,l = []): 
       self.l = l 
     def add(self,a): 
       self.l.append(a) 

def appender(a): 
     obj = intlist() 
     obj.add(a) 
     print obj.l 

if __name__ == "__main__": 
     for i in range(5): 
       appender(i) 

Una función crea una instancia de intlist y pide a este nuevo ejemplo del método append en la instancia atribuir l.

cómo se produce la salida de este código es:

[0]

[0, 1]

[0, 1, 2]

[0, 1, 2 , 3]

[0, 1, 2, 3, 4]

? Si cambio

obj = intlist() 

con

obj = intlist(l=[]) 

consigo la salida deseada

[0]

[1]

[2]

[3]

[4]

¿Por qué sucede esto?

Gracias

+0

1 de este texto como una pregunta y admitir culpa del comienzo. ¡Así es como aprendemos! :) – jathanism

+0

Relacionados: http://stackoverflow.com/questions/1011431/python-things-one-must-avoid –

+0

Gracias a todos, ahora que lo tengo, debo prestar más atención a lo que uso como valor predeterminado. Gracias de nuevo :) –

Respuesta

14

Ah, usted ha golpeado una de las trampas comunes de Python: valores por defecto se calculan una vez, a continuación, volver a utilizarse. Por lo tanto, cada vez que se invoca __init__, se utiliza la misma lista .

Ésta es la manera Pythonic de hacer lo que quiere:

def __init__(self, l=None): 
    self.l = [] if l is None else l 

Por un poco más información, echa un vistazo a the Python docs (especialmente alrededor de tres párrafos después de ese punto).

Editar: Hay a much better description in another answer.

+4

Right. En general, probablemente no desee utilizar tipos mutables como valores predeterminados. – prestomation

+0

Una pequeña nota: en mi respuesta inicial, utilicé 'self.l = l o []' ... que es, en este caso, probablemente correcto, pero es un hábito peligroso (por ejemplo, esto: 'my_list = [] ; intlist (mi_lista); my_list.append (4) 'podría no hacer lo que quieras). –

+0

+1: Problema estándar: objetos mutables como valores predeterminados. Consulte todos estos para obtener explicaciones: http://stackoverflow.com/search?q=%5Bpython%5D+mutable+default+values ​​ –

1

El comportamiento se debe a las llamadas de su cuota de __init__ método de la misma lista predeterminada.

Probar:

class intlist: 
     def __init__(self, l): 
       self.l = l if (l is not None) else [] 
     def add(self,a): 
       self.l.append(a) 

EDIT: Uso is not, por SilentGhost

+0

'is' es una prueba idiomática para' None' – SilentGhost

3

El problema es que cuando usted está diciendo

def __init__(self,l = []): 

le está diciendo a Python para utilizar la misma lista, [], para cada invocación del constructor. Por lo tanto, cada vez que se llame a obj = intlist(), se agrega la misma lista.

En su lugar, lo que debe hacer es establecer l en un valor predeterminado de None, que es un escalar (por lo que su código funcionará como se espera si se usa varias veces). Luego, si l es None, inicialice un nuevo miembro de clase como []. De lo contrario, simplemente asigne la variable miembro a l.

0

Tenga cuidado con los parámetros predeterminados de tipos como listas y dicts. Cada instancia de intlist obtiene ese mismo objeto de lista del parámetro predeterminado.

4

Cuando establece el valor predeterminado de l=[] en __init__, en realidad está usando la misma lista cada vez. En su lugar, podría intentar algo como:

class intlist: 
    def __init__(self, l=None): 
     if l is None: 
      self.l = [] 
     else: 
      self.l = l 
+1

+1, 'is None' es exactamente la forma correcta de comprobarlo aquí (no' == None' o checks simplemente basados ​​en el valor de verdad de 'l' como sugieren otras respuestas!). –

1

obj = intlist() llama a su función __init__() que utiliza la misma matriz para cada instancia de la clase.

obj = intlist(l=[]) crea una nueva matriz para cada instancia.

Cuestiones relacionadas