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



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



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

822   10  

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

The Python Tutorial содержит хорошее объяснение, как это работает, наряду с некоторыми хорошими примерами.

для люди, использующие 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-это просто словарь, который добавляется к параметрам.

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

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

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

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-функция.

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

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

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

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

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

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

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

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

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

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

опущение * в кортеж аргументы:

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 должен быть последним аргументом

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

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

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

Comments

    Ничего не найдено.