2011-05-02 18 views
6

¿Existe alguna forma más sucinta de escribir esto?Pasar argumentos de palabras clave a una función cuando los nombres de las variables locales son los mismos que los nombres de los parámetros de funciones

f(a=a, b=b, c=c, d=d, e=e) 

Antecedentes: Tengo una función con demasiados argumentos

f(a, b, c, d, e): 
    pass 

que mi programa tengo las variables locales que se denominan exactamente igual que los parámetros de la función.

a, b, c, d, e = range(5) 

Me gustaría llamar a la función con argumentos de palabra clave. Dado que las variables tienen el mismo nombre, así es como se vería la llamada.

g = f(a=a, b=b, c=c, d=d, e=e) # this can get very long 

Por supuesto, puedo pasar los aruguments utilizando la posición en lugar de palabras clave como esto

g = f(a, b, c, d, e) 

Pero a, b, c, d, e son sólo los nombres de las variables en este ejemplo y se es fácil ver el orden correcto. Sin embargo, desafortunadamente las variables en mi programa se nombran de manera más complicada y no hay un orden natural fácilmente discernible. Así que realmente me gusta pasarlos por palabra clave para evitar cualquier error.

Respuesta

5

Se podría hacer algo como lo siguiente:

a, b, c, d, e = range(5) 
arg_dict = lambda l: dict((k, globals()[k]) for k in l.split(', ')) 

arg_dict('a, b, c, d, e') => {'a': 0, 'c': 2, 'b': 1, 'e': 4, 'd': 3}, para que pueda llamar a su función como esta:

f(**arg_dict('a, b, c, d, e')) 

Esto le da la posibilidad de especificar exactamente cuáles son las variables que desea utilizar. Un método alternativo para esto que no utiliza globals() sería usar eval(), pero podría hacer que el uso de la lambda sea potencialmente inseguro.

arg_dict = lambda l: dict(zip(l.split(', '), eval(l))) 

Si prefiere pasar locals() como argumento en lugar de utilizar globals() en el lambda se puede utilizar lo siguiente:

arg_dict = lambda l, d=locals(): dict((k, d[k]) for k in l.split(', ')) 
f(**arg_dict('a, b, c, d, e')) 

Gracias a senderle para los locals() sugerencias.

+0

Punto menor: ¿no debería ser 'locales'? – senderle

+0

El 'lambda' tiene su propio alcance, por lo que las variables locales de su ámbito contenedor no están en' locals() 'si se usa dentro del lambda (pero estarán en' globals() '). –

+0

Wunderbar! Esto es exactamente lo que estaba buscando. ¡Gracias! Estoy de acuerdo con @senderle en que podría usar 'locals()' en lugar de 'globals()'. –

1

¿Por qué no puedes usar ** kw aquí?

def foo(**kw): 
    for k,v in kw.items(): 
     print k,v 


foo(a=2) 
foo(a=3, b=4) 
foo(nonsene=True, blather=False) 
+0

Estoy de acuerdo en que sería la elección natural. Sin embargo, foo() se define en un módulo externo y no tengo control sobre cómo se define la función. –

+0

Una alternativa es definir bar(), como un contenedor para foo() y pasa los argumentos, pero me preguntaba si había una manera más fácil. –

1

locals() da sus variables locales, por lo que podría hacer

def somewhere(): 
    x = 3 # its a local 
    f(**locals()) # same as f(x=3) 

pero se puede ver cómo seguramente muy frágil que es esto.

+0

Estaba pensando en los locales también. Pero no parecía ser la forma "elegante" de resolver esto. Si todo falla, puede ser que me quede con la fuerza bruta!:) –

Cuestiones relacionadas