передать ** аргумент 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 аргументов. Так в чем же причина?


источник
5
Интересно, почему вы называете это **argsв коде? Возможно, это худшее из возможных имен, так как люди будут путать его с*args
Джон Ла Руи
1
Ну, я никогда не использую * args, поэтому я использую ** args ^^, но я могу изменить его.

Ответы:

155

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

Префикс словаря с помощью «**» позволяет распаковать словарь kwargsв аргументы ключевых слов.

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

«Аргументы ключевого слова» являются методами-ключами-значениями-параметрами.

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

GECCO
источник
5
Теперь я понимаю. Я думал, что ключевые слова и dict - это одно и то же.
13
«Любой словарь может быть расширен до ключевых слов путем добавления префикса ** во время вызова функции». <- это круто
1
См. Также: Документы Python о параметрах ключевых слов и распаковке списков аргументов
динозавр
8
Фактический пример кода сделает этот ответ значительно более понятным.
OrangeDog
13

**Синтаксис говорит Python для сбора ключевых слов аргументов в словарь. Он save2передает его как аргумент без ключевого слова (объект словаря). The 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 вместо ** args и просто использовать def func (аргумент, dict_var = 0) ... func (1, {1: "a", 2: "b"})
1

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

Если вы хотите передать параметр типа ключевого слова в аргумент ключевого слова, вам нужно указать ** перед вашим словарем, что означает ** args

проверить это для более подробной информации об использовании ** кВт

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

Кит Хо
источник
Значит, есть большая разница между ** kwargs и dict?
спасибо, мне всегда нравится читать больше о темах, которые я не понимаю.