Распаковка аргументов ключевого слова, но только те, которые соответствуют функции
Скажем, у меня есть функция:
def foo(a = None, b=None, c=None):
return "a:%s, b:%s, c:%s" % (a,b,c)
У меня есть словарь с некоторым (или ничем) из приведенных выше аргументов, но также с ключами, которые не названы аргументами в функции, например:
d = {'a':1, 'x':4, 'b':2, 'y':5}
Если я вызову следующее, я получу ошибку, потому что "x" и "y" не являются аргументами в аргументе функции foo.
foo(**d) # error
Есть ли элегантный способ передачи аргументов из словаря в функцию, но только те значения с ключами, которые соответствуют аргументам функции.
Пожалуйста, исправьте меня, если моя аргумент/параметр терминологии выключен.
Ответы
Ответ 1
@Ashwini Chaudhary имеет очень питоновский способ решения вашей проблемы. Однако для этого требуется изменить подпись вашей функции foo
.
Если вы не хотите изменять свою подпись функции, вы можете использовать интроспекцию, чтобы узнать, какие аргументы ожидает ваша функция:
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)
Ответ 2
def foo(a = None, b=None, c=None,**extras):
return "a:%s, b:%s, c:%s" % (a, b, c)
здесь **extras
будет собирать все дополнительные аргументы имени/ключевого слова.
Ответ 3
Интересный вопрос. Я думаю, что большинство людей в реальной жизни используют подход @Ashwini Chaudhary.
Я согласен с @Rodrigue в том, что есть моменты, когда вы не можете изменить сигнатуру вызова функции (возможно, кто-то еще модуль).
Когда это произойдет, Используйте декоратор функций
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
из functools держит строки __name__
и __doc__
в такте. Вы также можете:
- Посмотрите
FunctionMaker
из модуля декораторов, но это должно быть более многоразовым подходом.
- изменить newfoo, чтобы не пропускать лишние ключи без ключевых слов.