Какова цель и использование ** kwargs?

763

Каковы цели использования **kwargsв Python?

Я знаю, что вы можете сделать objects.filterна столе и передать **kwargsаргумент.  

Могу ли я сделать это для определения времени дельт т.е. timedelta(hours = time1)?

Как именно это работает? Это классы как «распаковка»? Как a,b=1,2?

Федерер
источник
27
Если вы столкнетесь с этим вопросом как я, см. Также: * args и ** kwargs?
sumid
3
Замечательно краткое объяснение здесь : «* собирает все позиционные аргументы в кортеже», «** собирает все ключевые аргументы в словаре». Ключевое слово - собирает .
OSA
24
Просто FYI: kwargsрасшифровывается KeyWord ARGumentS, то есть аргументы, которые установили ключи
Ричард де Вит

Ответы:

868

Вы можете использовать, **kwargsчтобы позволить вашим функциям принимать произвольное количество аргументов ключевого слова («kwargs» означает «аргументы ключевого слова»):

>>> def print_keyword_args(**kwargs):
...     # kwargs is a dict of the keyword args passed to the function
...     for key, value in kwargs.iteritems():
...         print "%s = %s" % (key, value)
... 
>>> print_keyword_args(first_name="John", last_name="Doe")
first_name = John
last_name = Doe

Вы также можете использовать **kwargsсинтаксис при вызове функций, создав словарь аргументов с ключевыми словами и передав его в вашу функцию:

>>> kwargs = {'first_name': 'Bobby', 'last_name': 'Smith'}
>>> print_keyword_args(**kwargs)
first_name = Bobby
last_name = Smith

Python Учебник содержит хорошее объяснение того , как она работает, наряду с некоторыми хорошими примерами.

<- Update ->

Для людей, использующих Python 3, вместо iteritems () используйте items ()

Пяр Висландер
источник
1
@ yashas123 Нет; если вы зацикливаетесь на чем-то пустом, ничего не происходит, поэтому любой код, следующий за ним, будет работать нормально.
JG
330

Распаковка словарей

** распаковывает словари.

Эта

func(a=1, b=2, c=3)

такой же как

args = {'a': 1, 'b': 2, 'c':3}
func(**args)

Это полезно, если вам нужно построить параметры:

args = {'name': person.name}
if hasattr(person, "address"):
    args["address"] = person.address
func(**args)  # either expanded to func(name=person.name) or
              #                    func(name=person.name, address=person.address)

Параметры упаковки функции

def setstyle(**styles):
    for key, value in styles.iteritems():      # styles is a regular dictionary
        setattr(someobject, key, value)

Это позволяет вам использовать функцию следующим образом:

setstyle(color="red", bold=False)
Георг Шолли
источник
13
это kwarg это просто имя переменной правильно? так что я могу использовать def func (** args): и это будет работать?
Шрирам
11
@Sriram: Верно. Звездочки важны. kwargs это просто имя, которое он дает, если нет лучшего. (Обычно это так.)
Георг Шолли,
54
@Sriram: для удобства чтения вы должны придерживаться kwargs - другие программисты оценят это.
Johndodo
12
** do unpack dictionaries.>> Сумасшедший / конечно! +1 за объяснение этого бита.
Марк
13
Примечание: .iteritems()был переименован .items()в Python 3.
fnkr
67

kwargs - это просто словарь, который добавляется к параметрам.

Словарь может содержать пары ключ-значение. И это карги. Хорошо, это как.

Зачем не все так просто.

Например (очень гипотетически) у вас есть интерфейс, который просто вызывает другие подпрограммы для выполнения работы:

def myDo(what, where, why):
   if what == 'swim':
      doSwim(where, why)
   elif what == 'walk':
      doWalk(where, why)
   ...

Теперь вы получаете новый метод «езды»:

elif what == 'drive':
   doDrive(where, why, vehicle)

Но подождите минуту, появился новый параметр «транспортное средство» - вы не знали его раньше. Теперь вы должны добавить его в подпись myDo-функции.

Здесь вы можете бросить kwargs в игру - вы просто добавляете kwargs в подпись:

def myDo(what, where, why, **kwargs):
   if what == 'drive':
      doDrive(where, why, **kwargs)
   elif what == 'swim':
      doSwim(where, why, **kwargs)

Таким образом, вам не нужно менять сигнатуру вашей интерфейсной функции каждый раз, когда некоторые из вызываемых вами подпрограмм могут измениться.

Это только один хороший пример, который вы могли бы найти полезными для kwargs.

Юргена
источник
46

Исходя из того, что хороший пример иногда лучше длинного дискурса, я напишу две функции, использующие все средства передачи аргументов переменных Python (как позиционные, так и именованные аргументы). Вы должны легко увидеть, что он делает самостоятельно:

def f(a = 0, *args, **kwargs):
    print("Received by f(a, *args, **kwargs)")
    print("=> f(a=%s, args=%s, kwargs=%s" % (a, args, kwargs))
    print("Calling g(10, 11, 12, *args, d = 13, e = 14, **kwargs)")
    g(10, 11, 12, *args, d = 13, e = 14, **kwargs)

def g(f, g = 0, *args, **kwargs):
    print("Received by g(f, g = 0, *args, **kwargs)")
    print("=> g(f=%s, g=%s, args=%s, kwargs=%s)" % (f, g, args, kwargs))

print("Calling f(1, 2, 3, 4, b = 5, c = 6)")
f(1, 2, 3, 4, b = 5, c = 6)

И вот вывод:

Calling f(1, 2, 3, 4, b = 5, c = 6)
Received by f(a, *args, **kwargs) 
=> f(a=1, args=(2, 3, 4), kwargs={'c': 6, 'b': 5}
Calling g(10, 11, 12, *args, d = 13, e = 14, **kwargs)
Received by g(f, g = 0, *args, **kwargs)
=> g(f=10, g=11, args=(12, 2, 3, 4), kwargs={'c': 6, 'b': 5, 'e': 14, 'd': 13})
Kriss
источник
28

Motif: *argsи **kwargsслужит заполнителем для аргументов, которые необходимо передать в вызов функции

используя *argsи **kwargsдля вызова функции

def args_kwargs_test(arg1, arg2, arg3):
    print "arg1:", arg1
    print "arg2:", arg2
    print "arg3:", arg3

Теперь мы будем использовать *argsдля вызова определенной выше функции

#args can either be a "list" or "tuple"
>>> args = ("two", 3, 5)  
>>> args_kwargs_test(*args)

результат:

arg1: два
arg2: 3
arg3: 5


Теперь с помощью **kwargsвызова той же функции

#keyword argument "kwargs" has to be a dictionary
>>> kwargs = {"arg3":3, "arg2":'two', "arg1":5}
>>> args_kwargs_test(**kwargs)

результат:

arg1: 5
arg2: два
arg3: 3

Итог: *argsне имеет интеллекта, он просто интерполирует переданные аргументы к параметрам (в порядке слева направо), в то время как **kwargsведет себя разумно, помещая соответствующее значение в требуемое место

kmario23
источник
24
  • kwargsв **kwargsэто просто имя переменной. Вы можете очень хорошо иметь**anyVariableName
  • kwargsрасшифровывается как «ключевые аргументы». Но я считаю, что их лучше называть «именованными аргументами», так как это просто аргументы, передаваемые вместе с именами (я не нахожу никакого значения для слова «ключевое слово» в термине «ключевые слова аргументы». Я думаю, что «ключевое слово» обычно означает слова, зарезервированные языком программирования и, следовательно, не используемые программистом для имен переменных. В случае с kwargs такого не происходит.). Итак, мы даем имена param1 и param2двух значений параметров , передаваемых в функцию следующим образом : func(param1="val1",param2="val2")вместо прохождения только значения: func(val1,val2). Таким образом, я считаю, что их следует называть «произвольным числом именованных аргументов», поскольку мы можем указать любое количество этих параметров (то естьfuncfunc(**kwargs)

Поэтому, как говорится, позвольте мне сначала объяснить «именованные аргументы», а затем «произвольное количество именованных аргументов» kwargs.

Именованные аргументы

  • именованные аргументы должны следовать позиционным аргументам
  • порядок именованных аргументов не важен
  • пример

    def function1(param1,param2="arg2",param3="arg3"):
        print("\n"+str(param1)+" "+str(param2)+" "+str(param3)+"\n")
    
    function1(1)                      #1 arg2 arg3   #1 positional arg
    function1(param1=1)               #1 arg2 arg3   #1 named arg
    function1(1,param2=2)             #1 2 arg3      #1 positional arg, 1 named arg
    function1(param1=1,param2=2)      #1 2 arg3      #2 named args       
    function1(param2=2, param1=1)     #1 2 arg3      #2 named args out of order
    function1(1, param3=3, param2=2)  #1 2 3         #
    
    #function1()                      #invalid: required argument missing
    #function1(param2=2,1)            #invalid: SyntaxError: non-keyword arg after keyword arg
    #function1(1,param1=11)           #invalid: TypeError: function1() got multiple values for argument 'param1'
    #function1(param4=4)              #invalid: TypeError: function1() got an unexpected keyword argument 'param4'

Произвольное количество именованных аргументов kwargs

  • Последовательность параметров функции:
    1. позиционные параметры
    2. формальный параметр, фиксирующий произвольное количество аргументов (с префиксом *)
    3. именованные формальные параметры
    4. формальный параметр захватывает произвольное количество именованных параметров (с префиксом **)
  • пример

    def function2(param1, *tupleParams, param2, param3, **dictionaryParams):
        print("param1: "+ param1)
        print("param2: "+ param2)
        print("param3: "+ param3)
        print("custom tuple params","-"*10)
        for p in tupleParams:
            print(str(p) + ",")
        print("custom named params","-"*10)
        for k,v in dictionaryParams.items():
            print(str(k)+":"+str(v))
    
    function2("arg1",
              "custom param1",
              "custom param2",
              "custom param3",
              param3="arg3",
              param2="arg2", 
              customNamedParam1 = "val1",
              customNamedParam2 = "val2"
              )
    
    # Output
    #
    #param1: arg1
    #param2: arg2
    #param3: arg3
    #custom tuple params ----------
    #custom param1,
    #custom param2,
    #custom param3,
    #custom named params ----------
    #customNamedParam2:val2
    #customNamedParam1:val1

Передача переменных кортежа и dict для пользовательских аргументов

Чтобы закончить это, позвольте мне также отметить, что мы можем пройти

  • «формальный параметр, фиксирующий произвольное количество аргументов» в качестве переменной кортежа и
  • «формальный параметр, фиксирующий произвольное количество именованных параметров» в качестве переменной dict

Таким образом, тот же вышеупомянутый вызов может быть сделан следующим образом:

tupleCustomArgs = ("custom param1", "custom param2", "custom param3")
dictCustomNamedArgs = {"customNamedParam1":"val1", "customNamedParam2":"val2"}

function2("arg1",
      *tupleCustomArgs,    #note *
      param3="arg3",
      param2="arg2", 
      **dictCustomNamedArgs     #note **
      )

Наконец обратите внимание * и **на вызовы функций выше. Если мы их опускаем, мы можем получить плохие результаты.

Опуская *в кортеж args:

function2("arg1",
      tupleCustomArgs,   #omitting *
      param3="arg3",
      param2="arg2", 
      **dictCustomNamedArgs
      )

печать

param1: arg1
param2: arg2
param3: arg3
custom tuple params ----------
('custom param1', 'custom param2', 'custom param3'),
custom named params ----------
customNamedParam2:val2
customNamedParam1:val1

Выше кортежа ('custom param1', 'custom param2', 'custom param3') печатается как есть.

Опущенные dictаргументы:

function2("arg1",
      *tupleCustomArgs,   
      param3="arg3",
      param2="arg2", 
      dictCustomNamedArgs   #omitting **
      )

дает

dictCustomNamedArgs
         ^
SyntaxError: non-keyword arg after keyword arg
Mahesha999
источник
3
Я полагаю, что keywordтерминология исходит из того факта, что вы передаете в dict, который является базой данных пар ключ-значение.
crobar
Вы имеете в виду слово «ключ» в парах «ключ» - значение? Также его обычно не называют базой данных, но словарь. Но до сих пор не удалось найти какое-либо значение для использования слова «ключевое слово».
Mahesha999
9

Кроме того, вы также можете смешивать различные способы использования при вызове функций kwargs:

def test(**kwargs):
    print kwargs['a']
    print kwargs['b']
    print kwargs['c']


args = { 'b': 2, 'c': 3}

test( a=1, **args )

дает этот вывод:

1
2
3

Обратите внимание, что ** kwargs должен быть последним аргументом

Philipp
источник
5

kwargs - это синтаксический сахар для передачи именных аргументов в виде словарей (для func) или словарей в качестве именованных аргументов (для func)


источник
5

Вот простая функция, которая служит для объяснения использования:

def print_wrap(arg1, *args, **kwargs):
    print(arg1)
    print(args)
    print(kwargs)
    print(arg1, *args, **kwargs)

Любые аргументы, которые не указаны в определении функции, будут помещены в argsсписок или kwargsсписок, в зависимости от того, являются ли они ключевыми аргументами или нет:

>>> print_wrap('one', 'two', 'three', end='blah', sep='--')
one
('two', 'three')
{'end': 'blah', 'sep': '--'}
one--two--threeblah

Если вы добавите ключевой аргумент, который никогда не будет передан в функцию, возникнет ошибка:

>>> print_wrap('blah', dead_arg='anything')
TypeError: 'dead_arg' is an invalid keyword argument for this function
naught101
источник
1

Вот пример, который, я надеюсь, будет полезен:

#! /usr/bin/env python
#
def g( **kwargs) :
  print ( "In g ready to print kwargs" )
  print kwargs
  print ( "in g, calling f")
  f ( **kwargs )
  print ( "In g, after returning from f")

def f( **kwargs ) :
  print ( "in f, printing kwargs")
  print ( kwargs )
  print ( "In f, after printing kwargs")


g( a="red", b=5, c="Nassau")

g( q="purple", w="W", c="Charlie", d=[4, 3, 6] )

Когда вы запускаете программу, вы получаете:

$ python kwargs_demo.py 
In g ready to print kwargs
{'a': 'red', 'c': 'Nassau', 'b': 5}
in g, calling f
in f, printing kwargs
{'a': 'red', 'c': 'Nassau', 'b': 5}
In f, after printing kwargs
In g, after returning from f
In g ready to print kwargs
{'q': 'purple', 'c': 'Charlie', 'd': [4, 3, 6], 'w': 'W'}
in g, calling f
in f, printing kwargs
{'q': 'purple', 'c': 'Charlie', 'd': [4, 3, 6], 'w': 'W'}
In f, after printing kwargs
In g, after returning from f

Ключевым моментом здесь является то, что переменное число именованных аргументов в вызове переводится в словарь в функции.

user1928764
источник
0

Это простой пример для понимания распаковки Python ,

>>> def f(*args, **kwargs):
...    print 'args', args, 'kwargs', kwargs

например, 1:

>>>f(1, 2)
>>> args (1,2) kwargs {} #args return parameter without reference as a tuple
>>>f(a = 1, b = 2)
>>> args () kwargs {'a': 1, 'b': 2} #args is empty tuple and kwargs return parameter with reference as a dictionary
Мохидин бен Мухаммед
источник
0

В Java вы используете конструкторы для перегрузки классов и допускаете несколько входных параметров. В python вы можете использовать kwargs для обеспечения аналогичного поведения.

Пример Java: https://beginnersbook.com/2013/05/constructor-overloading/

пример Python:

class Robot():
    # name is an arg and color is a kwarg
    def __init__(self,name, color='red'):
        self.name = name
        self.color = color

red_robot = Robot('Bob')
blue_robot = Robot('Bob', color='blue')

print("I am a {color} robot named {name}.".format(color=red_robot.color, name=red_robot.name))
print("I am a {color} robot named {name}.".format(color=blue_robot.color, name=blue_robot.name))

>>> I am a red robot named Bob.
>>> I am a blue robot named Bob.

просто еще один способ думать об этом.

Эйдан Мелен
источник
0

Ключевое слово Аргументы часто сокращаются до kwargs в Python. В компьютерном программировании ,

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

Использование двух звездочек перед именем параметра, ** kwargs , происходит, когда неизвестно, сколько аргументов ключевого слова будет передано в функцию. Когда это так, это называется Аргументы произвольных / подстановочных слов.

Одним из примеров этого являются функции приемника Джанго .

def my_callback(sender, **kwargs):
    print("Request finished!")

Обратите внимание, что функция принимает аргумент отправителя вместе с аргументами с подстановочными словами (** kwargs); все обработчики сигналов должны принимать эти аргументы. Все сигналы отправляют аргументы ключевых слов и могут изменить эти аргументы в любое время. В случае request_finished он задокументирован как отправка без аргументов, что означает, что у нас может возникнуть желание записать нашу обработку сигналов как my_callback (sender).

Это было бы неправильно - на самом деле, Django выдаст ошибку, если вы сделаете это. Это потому, что в любой момент аргументы могут быть добавлены к сигналу, и ваш получатель должен иметь возможность обрабатывать эти новые аргументы.

Обратите внимание, что он не должен называться kwargs , но должен иметь ** (название kwargs является условным обозначением).

Тиаго Мартинс Перес 李大仁
источник