2012-02-24 6 views
4

Предположим, у меня есть функция, что я не контролирую, который выглядит примерно так:Как передать членам в Словаре к функции

def some_func(foo, bar, bas, baz): 
    do_something() 
    return some_val 

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

some_func(foo=mydict['foo'], 
      bar=mydict['bar'], 
      bas=mydict['bas'], 
      baz=mydict['baz']) 

Есть ли какой-нибудь элегантный способ, которым я мог бы воспользоваться тем, что ключи совпадают с Parms сделать это менее многословно? Я знаю, что могу передать весь дикт, но скажем, я либо не хочу, либо не могу изменить функцию, чтобы принять один дик, а не отдельные аргументы.

Спасибо, Джерри

ответ

11

Вот что ** аргумент распаковка для:

some_func(**mydict) 

Смотрите также Unpacking argument lists в учебнике Python.

+0

Это работает, если есть дополнительные элементы dict, которые не являются допустимыми именами аргументов? –

+0

Он работает, если функция принимает ключевые слова args с использованием символа '**', и в этом случае он получит дополнительные в качестве отдельного словаря и, вероятно, игнорирует их. В противном случае нет. – kindall

+1

Если вы хотите передать неизвестное количество аргументов, вы можете дать своей функции параметр '** kwargs'. http://www.saltycrane.com/blog/2008/01/how-to-use-args-and-kwargs-in-python/ – dm03514

5

Как отмечает Свен, вы можете передать dict функции с использованием ** распаковки. Но если dict содержит ключи, которые не являются именами аргументов целевой функции, это работает, только если вызываемая вами функция принимает аргументы ключевых слов, используя нотацию **. Если это не так, вы получите сообщение об ошибке.

Если функция, которую вы вызываете, не имеет параметра **kwargs, самый простой способ ее обработки - добавить ее. Но если вы не можете сделать это, у вас есть несколько подходов:

1) Написать функцию обертку:

def wrapper(foo, bar, baz, quux, **kwargs): 
    return some_func(foo, bar, baz, quux) 

wrapper(**mydict) 

2) Написать функцию для извлечения только ключи Dict вам нужно:

def extract(dikt, keys): 
    return dict((k, dikt[k]) for k in keys.split()) 

some_func(**extract(mydict, "foo bar baz quux")) 

3) Напишите функцию, которая исследует функцию, которую вы вызываете, и извлекает нужные вам слова из словаря - в основном то же самое, что и # 2, за исключением того, что вам не нужно «повторять себя» столько же.

def call_with_dict(func, dikt): 
    func(**dict((k, dikt[k]) for k in 
     func.func_code.co_varnames[:func.func_code.co_argcount])) 

call_with_dict(some_func, my_dict) 

Обратите внимание, что это не позволяет пропустить аргументы, которые имеют значения по умолчанию в сигнатуре функции. Вы могли бы сделать дополнительную интроспекцию, чтобы это разрешило (длина func.func_defaults определяет, какие аргументы имеют значения по умолчанию).

Эта интроспекция для Python 2.x, Python 3 и более поздних версий, вероятно, нуждается в некоторой настройке. По этой причине я предпочитаю один из первых двух методов.

PS - Спасибо Свену за то, что он поймал мой недостающий ** в моем втором подходе.

+0

Kindall, спасибо за дальнейшее разъяснение. – zenzic

+0

Я бы предложил использовать 'argnames = set (inspect.getargspec (action) [0]); kwargs = {k: v для k, v в dikt.iteritems(), если k в argnames} 'в версии inrospection. Это работает как на Python 2.7, так и на 3.x (а также на более ранних версиях, если вы используете 'dict()' вместо понимания dicitonary). Я также перестроил код, чтобы исключить аргументы, которые имеют значения по умолчанию. –

+0

Niiiiiiiiiiice. – kindall

Смежные вопросы