Передача словника функції як параметри ключового слова


346

Я б хотів викликати функцію в python за допомогою словника.

Ось код:

d = dict(param='test')

def f(param):
    print(param)

f(d)

Це відбитки, {'param': 'test'}але я хотів би, щоб він просто надрукував test.

Я хотів би, щоб він працював аналогічно для більшої кількості параметрів:

d = dict(p1=1, p2=2)
def f2(p1, p2):
    print(p1, p2)
f2(d)

Чи можливо це?

Відповіді:


528

Зрозумів це для себе врешті-решт. Це просто, мені просто не вистачало оператора **, щоб розпакувати словник

Тож мій приклад стає:

d = dict(p1=1, p2=2)
def f2(p1,p2):
    print p1, p2
f2(**d)

57
якщо ви хочете, щоб це допомогло іншим, вам слід перефразувати своє запитання: проблема не в тому, щоб передати словник, те, що ви хотіли, було перетворення диктату в параметри ключових слів
Хав'єр

11
Варто зауважити, що ви також можете розпакувати списки до позиційних аргументів: f2 (* [1,2])
Метью Тревор

10
"dereference": звичайний термін, в цьому контексті Python, - "розпакувати". :)
mipadi

2
Це чудово, просто використовував його з argparse / __ dict__, щоб зробити його дійсно простим для аналізу аргументу командного рядка безпосередньо на параметри об’єкта класу.
Хорус

1
з якої причини ми хотіли б розпакувати словник, передаючи його як аргумент функції?
Мона Джалал

128
In[1]: def myfunc(a=1, b=2):
In[2]:    print(a, b)

In[3]: mydict = {'a': 100, 'b': 200}

In[4]: myfunc(**mydict)
100 200

Кілька додаткових подробиць, які можуть бути корисними для мене (питання, які у мене виникли після того, як прочитати це, перевірити)

  1. Функція може мати параметри, які не входять до словника
  2. Ви не можете замінити параметр, який вже є у словнику
  3. У словнику не може бути параметрів, які відсутні у функції.

Приклади:

Число 1: Функція може мати параметри, які не включені до словника

In[5]: mydict = {'a': 100}
In[6]: myfunc(**mydict)
100 2

Число 2: Ви не можете замінити параметр, який вже є у словнику

In[7]: mydict = {'a': 100, 'b': 200}
In[8]: myfunc(a=3, **mydict)

TypeError: myfunc() got multiple values for keyword argument 'a'

Число 3: У словнику не може бути параметрів, які відсутні у функції.

In[9]:  mydict = {'a': 100, 'b': 200, 'c': 300}
In[10]: myfunc(**mydict)

TypeError: myfunc() got an unexpected keyword argument 'c'

Як вимагається в коментарях, рішенням № 3 є рішення про фільтрацію словника на основі аргументів ключових слів, доступних у функції:

In[11]: import inspect
In[12]: mydict = {'a': 100, 'b': 200, 'c': 300}
In[13]: filtered_mydict = {k: v for k, v in mydict.items() if k in [p.name for p in inspect.signature(myfunc).parameters.values()]}
In[14]: myfunc(**filtered_mydict)
100 200

Інший варіант - прийняти (ігнорувати) додаткові кварги у вашій функції:

In[15]: def myfunc2(a=None, **kwargs):
In[16]:    print(a)

In[17]: mydict = {'a': 100, 'b': 200, 'c': 300}

In[18]: myfunc2(**mydict)
100

Зауважте далі, ніж ви можете використовувати позиційні аргументи та списки чи кортежі ефективно так само, як і kwargs, ось більш досконалий приклад, що включає як позиційні, так і ключові слова:

In[19]: def myfunc3(a, *posargs, b=2, **kwargs):
In[20]:    print(a, b)
In[21]:    print(posargs)
In[22]:    print(kwargs)

In[23]: mylist = [10, 20, 30]
In[24]: mydict = {'b': 200, 'c': 300}

In[25]: myfunc3(*mylist, **mydict)
10 200
(20, 30)
{'c': 300}

4
Використання розпакування з print.format особливо корисно. наприклад:'hello {greeting} {name}'.format( **{'name': 'Andrew', 'greeting': 'Mr'})
Martlark

Старе питання, але все ще дуже актуальне. Дякуємо за детальну відповідь. Чи знаєте ви будь-які способи подолати справу 3? Значить пітонічно відображати елементи словника за параметрами функції, коли в словнику є більше елементів, ніж є параметри?
Спенсер

2
@spencer у відповідь було додано рішення.
Девід Паркс

33

У python це називається "розпакування", і ви можете трохи дізнатися про це у підручнику . Документація це відстійно, я погоджуюсь, особливо через те, наскільки це фантастично корисно.


20
Краще скопіювати відповідний вміст посилання у свою відповідь, а не покладатися на посилання, яке збереглось до кінця часу.
Річард

3
@Richard - це глибока філософська думка щодо Інтернету, з якою я не могла погодитися більше від душі! На жаль, мені не вистачає місця в цьому запасі, щоб поділитися своїм чудовим доказом ...
llimllib

@llimllib, мені доведеться запитати доктора Вілласа тоді!
Річард

6

Ось ви працюєте - працює будь-який інший ітерабельний:

d = {'param' : 'test'}

def f(dictionary):
    for key in dictionary:
        print key

f(d)

Здається, що люди заперечують це, оскільки вони відповіли на первісне запитання, а не на перефразоване питання. Я пропоную просто видалити цю публікацію зараз.
dotancohen

@dotancohen ні, це ніколи не було правильним, він не вдається другому блоку коду, який завжди був з питанням. Це було сприйнято занадто буквально, приклад був прикладом.
Дейв Хіллєр

Однак він відповідає на питання, але просто не робить це через розпакування словника. Його підхід цілком справедливий на основі поставленого питання.
Natecat
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.