2012-04-12 15 views
5

Creo que muchas personas han visto la función de la pitón que recibe los parámetros predeterminados. Por ejemplo:Dónde está el parámetro predeterminado en la función de Python

def foo(a=[]): 
    a.append(3) 
    return a 

Si llamamos esta función utilizando foo(), la salida anexará número entero '3' cada vez después de la llamada.

Cuando se define esta función, se define un objeto de función llamado 'foo' en el entorno actual, y también se evalúan los valores de parámetros predeterminados en este momento. Cada vez que se llama a la función sin un parámetro, el valor del parámetro evaluado cambiará de acuerdo con el código.

Mi pregunta es ¿Dónde está este parámetro evaluado? ¿Está en el objeto de función o está en el objeto de método al llamar a la función? Dado que todo en python es un objeto, debe haber un lugar para contener el nombre-> enlace de valor de 'a' -> parámetro evaluado. ¿Estoy pensando demasiado en este problema?

Respuesta

10

Como ya se ha dicho, los valores predeterminados se almacenan en el objeto de función.

Por ejemplo, en CPython usted puede hacer esto:

>>> def f(a=[]): 
...  pass 
... 
>>> f.func_defaults 
([],) 
>>> f.func_code.co_varnames 
('a',) 
>>> 

Sin embargo, co_varnames puede contener más de nombres de argumentos por lo que necesita un procesamiento adicional y estos atributos ni siquiera podría estar allí en otras implementaciones de Python. Por lo tanto se debe utilizar el módulo de inspect vez que se encarga de todos los detalles de implementación para usted:

>>> import inspect 
>>> spec = inspect.getargspec(f) 
>>> spec 
ArgSpec(args=['a'], varargs=None, keywords=None, defaults=([],)) 
>>> 

El ArgSpec es una tupla llamada para que pueda acceder a todos los valores como atributos:

>>> spec.args 
['a'] 
>>> spec.defaults 
([],) 
>>> 

A medida que el documentation dice, la tupla defaults siempre corresponde a los n últimos argumentos de args. Esto te da tu mapeo.

Para crear un diccionario que podría hacer esto:

>>> dict(zip(spec.args[-len(spec.defaults):], spec.defaults)) 
{'a': []} 
>>> 
4

Se une al objeto función, consulte foo.func_defaults:

>>> foo() 
>>> foo.func_defaults 
([3],) 
>>> foo() 
>>> foo.func_defaults 
([3, 3],) 

En caso si usted desea conseguir el mapeo de a en [], puede acceder a foo.func_code:

defaults = foo.func_defaults 
# the args are locals in the beginning: 
args = foo.func_code.co_varnames[:foo.func_code.co_argcount] 
def_args = args[-len(defaults):] # the args with defaults are in the end 
print dict(zip(def_args, defaults)) # {'a': []} 

(Pero, aparentemente, la versión del yak es mejor.)

+2

Sí, pero ¿dónde está la asignación de 'a' a' [] 'como la OP ha pedido? – MattH

+0

@MattH actualizó la respuesta, gracias. – bereal

4

Está en el objeto de función, en el func_defaults :

def f(a=[]): a.append(3) 

print f.func_defaults # ([],) 

f() 

print f.func_defaults # ([3],) 
+2

Sí, pero ¿dónde está el mapeo de a a [] como lo ha pedido el OP? – MattH

2

Se almacena en el atributo func_defaults del objeto función.

>>> foo.func_defaults 
([],) 
>>> foo() 
([3],) 
1

he encontrado una situación interesante: en Python 2.5.2 versión, prueba el 'foo()' función

>>> foo() 
[1] 
>>> foo() 
[1] 
>>> foo() 
[1] 

Debido a que los objetos de la función llamada son diferentes:

>>> id(foo()) 
4336826757314657360 
>>> id(foo()) 
4336826757314657008 
>>> id(foo()) 
4336826757314683160 

En 2.7.2 versión:

>>> foo() 
[1] 
>>> foo() 
[1, 1] 
>>> foo() 
[1, 1, 1] 

En este caso, el objeto es el mismo cada vez que llama a la función:

>>> id(foo()) 
29250192 
>>> id(foo()) 
29250192 
>>> id(foo()) 
29250192 

¿Hay algún problema con las diferentes versiones?

+0

No debería suceder. Asegúrese de estar usando * exactamente * las mismas funciones en ambas versiones. – yak

Cuestiones relacionadas