Понимание kwargs в Python

что пользы для **kwargs в Python?

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

10 ответов


можно использовать **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 Учебник содержит хорошее объяснение, как это работает, наряду с некоторыми хорошими примерами.

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


распаковка словари

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

этой

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)

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

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

В какой не так просто.

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

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

Теперь вы получаете новый метод "drive":

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

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

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

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

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

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


на основании того, что хороший образец иногда лучше, чем длинный дискурс, я напишу две функции, используя все средства передачи аргументов переменных 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})

мотив: *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
аргумент2: два
значение arg3: 3

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


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

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

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

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

    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 для пользовательских args

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

  • "формальный параметр, фиксирующий произвольное количество аргументов" как переменная кортежа и
  • "формальный параметр захвата произвольного числа именованных параметров" в качестве переменной 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

выше кортежа!--22--> печатается как есть.

опущение dict args:

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

дает

dictCustomNamedArgs
         ^
SyntaxError: non-keyword arg after keyword arg

в качестве дополнения вы также можете смешивать различные способы использования при вызове функций 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 должен быть последним аргументом


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


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

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

вот пример, который я надеюсь поможет:

#! /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

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