python - terminos - Desempaquetar argumentos de palabras clave, pero solo los que coinciden con la función
palabras reservadas python significado (3)
Digamos que tengo una 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 anteriores, pero también con claves que no tienen nombres en la función, por ejemplo:
d = {''a'': 1, ''x'': 4, ''b'': 2, ''y'': 5}
Si llamo a lo siguiente obtendré un error, porque ''x'' y ''y'' no son argumentos de palabras clave en la función foo.
foo(**d) # error
¿Existe una manera elegante de pasar los argumentos de un diccionario a una función, pero solo los valores con claves que coinciden con los argumentos de la función?
Por favor, corríjame si mi terminología de argumento / parámetro está desactivada.
@Ashwini Chaudhary tiene una forma muy pitónica de resolver tu problema. Sin embargo, requiere cambiar la firma de su función foo
.
Si no desea cambiar su firma de función, puede utilizar la introspection para averiguar qué argumentos espera su función:
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)
Interesante pregunta. Creo que la mayoría de las personas en la vida real utilizan el enfoque @Ashwini Chaudhary.
Estoy de acuerdo con @Rodrigue en que en ocasiones no se puede modificar la firma de llamada de la función (quizás el módulo de otra persona) .
Cuando eso suceda, usa un decorador de funciones.
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
from functools mantiene las cadenas __name__
y __doc__
en __doc__
. También podrías:
- mire a
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 adicionales sin palabras clave.
def foo(a = None, b=None, c=None,**extras):
return "a:%s, b:%s, c:%s" % (a, b, c)
aquí los **extras
recopilarán todos los argumentos adicionales con nombre / palabra clave.