передати аргумент ** kwargs до іншої функції з ** kwargs


152

Я не розумію наступного прикладу, скажемо, що я маю ці функції:

# python likes
def save(filename, data, **kwargs):
    fo = openX(filename, "w", **kwargs) # <- #1
    fo.write(data)
    fo.close()
# python doesnt like
def save2(filename, data, **kwargs):
    fo = openX(filename, "w", kwargs) # <- #2
    fo.write(data)
    fo.close()

def openX(filename, mode, **kwargs):
    #doing something fancy and returning a file object

Чому №1 - правильне рішення, а №2 - неправильне? **kwargsв основному є диктатом, тому, якщо я хочу передати аргумент до openX, я думаю, що правильний шлях був би без цього **і просто давав би дікт. Але python, очевидно, не подобається другий, і каже мені, що я дав 3 замість 2 аргументів. То яка причина цього?

python 

5
Цікаво, чому ви називаєте це **argsв коді. Це, можливо, найгірше можливе ім'я, оскільки люди будуть плутати його*args
Джон Ла Руй

1
Ну, я ніколи не використовую * args, тому я використовую ** args ^^, але добре, я можу це змінити.

Відповіді:


155

У другому прикладі ви наводите 3 аргументи: ім'я файлу, режим та словник ( kwargs). Але Python очікує: 2 формальних аргументи плюс аргументи ключових слів.

Префіксуючи словник "**", ви розпаковуєте словник kwargsдо аргументів ключових слів.

Словник (тип dict) - це єдина змінна, що містить пари ключ-значення.

"Аргументи ключових слів" - це метод-параметри ключових значень.

Будь-який словник може розпаковуватися до аргументів ключового слова, префіксуючи його **під час виклику функції.


5
тепер я розумію. Я думав, що ключові слова та диктат - це одне й те саме.

13
"Будь-який словник можна розширити до ключових слів, префіксуючи його ** під час виклику функції." <- thats cool


8
Фактичний приклад коду зробить цю відповідь значно зрозумілішою.
OrangeDog

13

**Синтаксис говорить Python для збору ключових слів аргументів в словник. Це save2передає його як аргумент, що не має ключового слова (об’єкт словника). Архів openXключових слів не бачить жодних аргументів, тому **argsне використовується. Це замість цього отримати третій не ключовий аргумент (словник). Щоб виправити це, змінити визначення openXфункції.

def openX(filename, mode, kwargs):
    pass

Дякую, але я також хочу використовувати openX без збереження, тому мені доводиться дотримуватися ключових слів. Я думав, що пропуск ключових слів в основному такий же, як і пропуск дикту, але я до цього часу не знав :)

@xMRW Вони не можуть бути тим самим, оскільки ви можете передавати словник як параметр будь-якій функції. Тоді ваш №1 є правильним.
Кіт

8

Розгорнувшись на відповідь @gecco, наступний приклад, який покаже вам різницю:

def foo(**kwargs):
    for entry in kwargs.items():
        print("Key: {}, value: {}".format(entry[0], entry[1]))

# call using normal keys:
foo(a=1, b=2, c=3)
# call using an unpacked dictionary:
foo(**{"a": 1, "b":2, "c":3})

# call using a dictionary fails because the function will think you are
# giving it a positional argument
foo({"a": 1, "b": 2, "c": 3})
# this yields the same error as any other positional argument
foo(3)
foo("string")

Тут ви можете побачити, як працює розпакування словника та чому надсилання фактичного словника не вдається


1

Тому що словник - це єдине значення. Вам потрібно використовувати розширення ключових слів, якщо ви хочете передати його як групу аргументів ключових слів.


Вибачте, але що таке "розширення ключових слів"? ти маєш на увазі, що я повинен використовувати dict_var замість ** аргументів і просто використовувати def func (аргумент, dict_var = 0) ... func (1, {1: "a", 2: "b"})

1

Для # 2 аргументи будуть лише формальним параметром зі значенням dict, але не параметром типу ключового слова.

Якщо ви хочете передати параметр типу ключового слова в аргумент ключового слова, вам потрібно вказати ** перед словником, що означає ** аргументи

перевірте це для отримання більш детальної інформації про використання ** кВт

http://www.saltycrane.com/blog/2008/01/how-to-use-args-and-kwargs-in-python/


Отже, велика різниця між ** кворгами та диктатом?

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