Какова цель и использование ** kwargs?
Каковы применения для **kwargs
в Python?
Я знаю, что вы можете сделать objects.filter
в таблице и передать аргумент **kwargs
.
Могу ли я это сделать и для определения дельта времени, т.е. timedelta(hours = time1)
?
Как именно он работает? Является ли это классом как "распаковка"? Как a,b=1,2
?
Ответы
Ответ 1
Вы можете использовать **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(), используйте пункты()
Ответ 2
Распаковка словарей
**
распаковывает словари.
Это
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)
Ответ 3
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.
Ответ 4
На том основании, что хороший образец иногда лучше длинного дискурса, я напишу две функции, используя все объекты передачи аргументов переменной 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})
Ответ 5
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
Bottomline: *args
не имеет интеллекта, он просто интерполирует переданные аргументы в параметры (в порядке слева направо), а **kwargs
ведет себя разумно, помещая соответствующее значение @в требуемое место
Ответ 6
-
kwargs
in **kwargs
- это просто имя переменной. Вы можете очень хорошо иметь **anyVariableName
-
kwargs
означает "аргументы ключевого слова". Но я считаю, что их лучше назвать "именованными аргументами", поскольку это просто аргументы, передаваемые вместе с именами (я не считаю какое-либо значение для слова "ключевое слово" в терминах "аргументы ключевых слов". Я думаю, что "ключевое слово" обычно означает слова, зарезервированные по языку программирования и, следовательно, не используемые программистом для имен переменных. В этой ситуации здесь не происходит.). Итак, мы даем имена
param1
и param2
до двух значений параметров, переданных функции следующим образом: func(param1="val1",param2="val2")
вместо передачи только значений: func(val1,val2)
. Таким образом, я считаю, что они должны быть соответствующим образом названы "произвольным числом именованных аргументов" , поскольку мы можем указать любое количество этих параметров (то есть аргументы), если func
имеет подпись func(**kwargs)
Так что, говоря, что позвольте мне сначала объяснить "именованные аргументы", а затем "произвольное количество именованных аргументов" kwargs
.
Именованные аргументы
- named 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
- Последовательность параметров функции:
- позиционные параметры
- формальный параметр, фиксирующий произвольное количество аргументов (с префиксом *)
- названные формальные параметры
- формальный параметр, фиксирующий произвольное количество именованных параметров (с префиксом **)
-
Пример
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
args:
function2("arg1",
*tupleCustomArgs,
param3="arg3",
param2="arg2",
dictCustomNamedArgs #omitting **
)
дает
dictCustomNamedArgs
^
SyntaxError: non-keyword arg after keyword arg
Ответ 7
В качестве дополнения вы также можете смешивать различные способы использования при вызове функций 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 должен быть последним аргументом
Ответ 8
kwargs являются синтаксическим сахаром для передачи аргументов имени в виде словарей (для func) или словарей в качестве именных аргументов (для func)
Ответ 9
Вот простая функция, которая объясняет использование:
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
Ответ 10
Вот пример, который, надеюсь, полезен:
#! /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
Ключ отнимает здесь то, что переменное число именованных аргументов в вызове переводится в словарь в функции.
Ответ 11
Это простой пример для понимания распаковки 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