2011-05-16 23 views
6

Duplicar posibles:
“Least Astonishment” in Python: The Mutable Default ArgumentPython: Diccionario como instancia de variable

Estoy muy confundido sobre el comportamiento de los diccionarios como variables de instancia de clase en Python 3. La manera en que yo lo entiendo , las variables de instancia en Python tienen almacenamiento por instancia, a diferencia de las variables de clase que son por clase (similar a lo que algunos otros idiomas llaman "estático").

Y esto parece ser cierto, excepto cuando la variable de instancia es un diccionario creado a partir de un parámetro predeterminado. Por ejemplo:

salidas
class Foo: 
    def __init__(self, values = dict()): 
     self.values = values 

f1 = Foo() 
f1.values["hello"] = "world" 

f2 = Foo() 
print(f2.values) 

Este programa:

{'hello': 'world'} 

Huh? ¿Por qué la instancia f2 tiene la misma instancia de diccionario que f1?

recibo el comportamiento esperado si no paso en un diccionario vacío como un parámetro por defecto, y justo asigno self.values a un diccionario vacío de forma explícita:

class Foo: 
    def __init__(self): 
     self.values = dict() 

Pero no puedo ver por qué esto debería hacer alguna diferencia

+1

Es posible que los parámetros predeterminados solo se evalúen una vez, cuando se carga la clase. De esta forma, simplemente está asignando la misma referencia como parámetro predeterminado. –

+0

El desbordamiento de pila tiene una bonita función de "Preguntas frecuentes" por etiqueta. Aquí están las preguntas más frecuentes para la etiqueta de Python: http://stackoverflow.com/questions/tagged/python?sort=faq&pagesize=30 Su pregunta se responde en la pregunta número 4. –

Respuesta

10

Esta es una sorpresa bien conocida en Python. Los parámetros predeterminados se evalúan cuando se define la función, no cuando se llama. Por lo tanto, su parámetro predeterminado es una referencia a un dict común. No tiene nada que ver con asignarlo a las variables de clase/instancia.

Si desea utilizar un parámetro predeterminado, utilice None, y comprobar que:

if values is None: 
    self.values = {} 
else: 
    self.values = values 
+1

Obtendrá el mismo comportamiento con una lista también – jaydel

+2

Obtiene el mismo comportamiento con * cada objeto * mutable. – delnan

2

Los valores por defecto sólo se evalúan una vez. ¿Quieres algo como esto:

class Foo: 
    def __init__(self, values = None): 
     self.values = values or dict() 

Si proporciona un values, que se acostumbrará. De lo contrario, values se evalúa como FALSE por el operador or y crea una nueva instancia de dict.

+2

Esto falla si algo falso se pasa como valores, p. Ej. una instancia vacía de una subclase 'dict' personalizada. – delnan

Cuestiones relacionadas