2009-10-18 30 views
24

chicos, acabo de empezar pitón recientemente y se confunden con los parámetros opcionales, decir que tengo el programa de la siguiente manera:Python parámetros opcionales

class B: 
    pass 

class A: 
    def __init__(self, builds = B()): 
     self.builds = builds 

si creo un doble

b = A() 
c = A() 

e imprimir sus formaciones

print b.builds 
print c.builds 

he encontrado que están usando exactamente el mismo objeto,

<__main__.B instance at 0x68ee0> 
<__main__.B instance at 0x68ee0> 

Pero no es lo que quiero, ya que si b cambiado algún estado interno de generaciones, el que está en c objeto también se cambiará.

¿Es posible volver a crear estos parámetros opcionales cada vez utilizando esta sintaxis de parámetros opcionales?

+15

¡Debe aceptar una respuesta si se solucionó el problema! Varias de las respuestas parecen muy informativas. Aunque la pregunta es antigua, creo que sería una buena idea dar una respuesta a su sello de aprobación – eipxen

+0

posible duplicado de ["Menos asombro" en Python: el argumento predeterminado mutable] (http://stackoverflow.com/ questions/1132941/least-atightishment-in-python-the-mutable-default-argument) –

Respuesta

6

Sí; los parámetros predeterminados se evalúan solo en el momento en que se define la función.

Una posible solución sería que el parámetro sea una clase en lugar de una instancia, a la

def foo(blah, klass = B): 
    b = klass() 
    # etc 
+0

En resumen, no puede usar un objeto mutable como valor predeterminado. –

+0

Claro que puedes. Las clases son mutables en Python. No tiene nada que ver con mutable/inmutable. –

+0

El uso de un objeto mutable conduce a la confusión exacta en esta pregunta. Cuando utiliza una clase como predeterminada, casi siempre crea una instancia para crear un objeto. La mutabilidad de la clase no importa porque no estás usando la clase directamente en la forma en que usas una lista o un diccionario. –

15

que tiene que hacer lo siguiente:

class A: 
    def __init__(self, builds=None): 
     if builds is None: 
      builds = B() 
     self.builds = builds 

Es una muy amplia -spread error, usando parámetros mutables como argumentos por defecto. hay muchos tontos probablemente en SO.

+1

así que vamos a encontrar un dup y cerrar éste? –

+2

El problema es este: no puede usar objetos mutables como valores predeterminados. Todos los duplicados anteriores han tratado de usar listas. Este es el primero que usa un objeto. Es el "problema estándar" de tratar de usar un objeto mutable como valor predeterminado. –

46

Necesita comprender cómo funcionan los valores predeterminados para usarlos de manera efectiva.

Las funciones son objetos. Como tal, tienen atributos. Entonces, si creo esta función:

>>> def f(x, y=[]): 
     y.append(x) 
     return y 

He creado un objeto. Aquí están sus atributos:

>>> dir(f) 
['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', 
'__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__',  
'__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', 
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 
'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 
'func_name'] 

Uno de ellos es func_defaults. Eso suena prometedor, ¿qué hay ahí?

>>> f.func_defaults 
([],) 

Esa es una tupla que contiene los valores predeterminados de la función. Si un valor predeterminado es un objeto, la tupla contiene una instancia de ese objeto.

Esto conduce a un comportamiento bastante contrario a la intuición si usted está pensando que f añade un elemento a una lista, devolviendo una lista que contiene sólo ese elemento si no se proporciona la lista:

>>> f(1) 
[1] 
>>> f(2) 
[1, 2] 

Pero si sabe que el valor por defecto es una instancia de objeto que se almacena en uno de los atributos de la función, que es mucho menos contrario a la intuición:

>>> x = f(3) 
>>> y = f(4) 
>>> x == y 
True 
>>> x 
[1, 2, 3, 4] 
>>> x.append(5) 
>>> f(6) 
[1, 2, 3, 4, 5, 6] 

Sabiendo esto, está claro que si se desea un valor por defecto del parámetro de una función que sea una lista nueva (o cualquier ob nuevo objeto), no se puede ocultar una instancia del objeto en func_defaults. Debe crear uno nuevo cada vez que se llame a la función:

>>>def g(x, y=None): 
     if y==None: 
      y = [] 
     y.append(x) 
     return y 
Cuestiones relacionadas