2012-06-16 8 views
16

Digamos que tiene una función:argumentos clave Desempaquetar, pero sólo los que responden a la función

def foo(a = None, b=None, c=None): 
    return "a:%s, b:%s, c:%s" % (a,b,c) 

Tengo un diccionario con algunos (o ninguno) de los argumentos anteriormente, sino también con las llaves que son que no se citan argumentos en la función, por ejemplo:

d = {'a':1, 'x':4, 'b':2, 'y':5} 

Si llamo a la siguiente voy a tener un error, porque no son argumentos clave en la función foo 'x' y 'y'.

foo(**d) # error 

¿Hay una manera elegante de pasar los argumentos de un diccionario a una función, pero sólo aquellos valores con claves que coinciden con los argumentos de la función.

Corrígeme si mi terminología de argumento/parámetro está desactivada.

Respuesta

7

@Ashwini Chaudhary tiene una manera muy pitonica de resolver su problema. Sin embargo, requiere cambiar la firma de su función foo.

Si no desea cambiar su firma de la función, se puede utilizar introspection para averiguar cuáles son los argumentos de su función espera:

arg_count = foo.func_code.co_argcount 
args = foo.func_code.co_varnames[:arg_count] 

args_dict = {} 
for k, v in d.iteritems(): 
    if k in args: 
     args_dict[k] = v 

foo(**args_dict) 
28
def foo(a = None, b=None, c=None,**extras): 
    return "a:%s, b:%s, c:%s" % (a, b, c) 

aquí el **extras recogerá todos los argumentos adicionales con nombre/palabra clave.

6

pregunta interesante. Creo que la mayoría de la gente en la vida real usa el enfoque de @Ashwini Chaudhary.

Estoy de acuerdo con @Rodrigue en que hay veces que no puede modificar la firma de llamada de la función (el módulo de alguien más tal vez).

Cuando eso sucede, Utilice un decorador función

from inspect import getargspec 
from funtools import wraps 

def allow_kwargs(foo): 
    argspec = getargspec(foo) 
    # if the original allows kwargs then do nothing 
    if argspec.keywords: 
     return foo 
    @wraps(foo) 
    def newfoo(*args, **kwargs): 
     #print "newfoo called with args=%r kwargs=%r"%(args,kwargs) 
     some_args = dict((k,kwargs[k]) for k in argspec.args if k in kwargs) 
     return foo(*args, **some_args) 
    return newfoo 


# with your function: 
@allow_kwargs 
def foo(a = None, b=None, c=None): 
    return "a:%s, b:%s, c:%s " % (a,b,c) 

# with someone_elses function: 
from some_place import foo 
foo = allow_kwargs(foo) 

@wraps de functools mantiene los __name__ y __doc__ cuerdas en el tacto. También podría:

  • mira en FunctionMaker desde el módulo de decoradores, pero este debería ser un enfoque más reutilizable.
  • modifique newfoo para permitir que no se pasen vars de palabras clave adicionales.
Cuestiones relacionadas