Вопрос по python – Распаковка ключевых аргументов, но только тех, которые соответствуют функции

18

Допустим, у меня есть функция:

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' apos; и 'y'; не являются ключевыми аргументами в функции foo.

foo(**d)  # error

Существует ли элегантный способ передачи аргументов из словаря в функцию, но только те значения с ключами, которые соответствуют аргументам функции.

Пожалуйста, исправьте меня, если моя терминология аргументов / параметров отключена.

Ваш Ответ

3   ответа
32
def foo(a = None, b=None, c=None,**extras):
    return "a:%s, b:%s, c:%s" % (a, b, c)

здесь**extras соберет все дополнительные аргументы с именами и ключевыми словами.

6

Интересный вопрос Я думаю, что большинство людей в реальной жизни используют подход @Ashwini Chaudhary.

Я согласен с @Rodrigue, что бывают случаи, когда вы не можете изменить сигнатуру вызова функции(someone else's module perhaps).

Когда это произойдет,Use a function decorator

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__ струны в такте. Вы также можете:

  • look at FunctionMaker from the decorators module but this should be a more reusable approach.
  • modify newfoo to allow extra non keyword vars to be not passed through.
7

@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)

Похожие вопросы