关于python:**kwargs的用途和用途是什么?

What is the purpose and use of **kwargs?

在python中,**kwargs有什么用途?

我知道你可以在桌子上做一个objects.filter,然后传递一个**kwargs参数。nbsp;

我也可以这样做来指定时间增量,即timedelta(hours = time1)

它到底是如何工作的?它是"解包"类吗?像a,b=1,2一样?


可以使用**kwargs让函数接受任意数量的关键字参数("kwargs"表示"关键字参数"):

1
2
3
4
5
6
7
8
>>> 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语法,方法是构造关键字参数字典并将其传递给函数:

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

Python教程包含了一个关于它如何工作的很好的解释,以及一些很好的例子。

<更新>

对于使用python 3而不是iteritems()的用户,请使用items()。


解包词典

**解包字典。

这个

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

是一样的

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

如果必须构造参数,它很有用:

1
2
3
4
5
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)

函数的包装参数

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

这样可以使用如下函数:

1
setstyle(color="red", bold=False)


Kwargs只是一个添加到参数中的字典。

字典可以包含键、值对。这就是禁运。好吧,就是这样。

事情并不那么简单。

例如(非常假设性的)您有一个接口,它只调用其他例程来完成该工作:

1
2
3
4
5
6
def myDo(what, where, why):
   if what == 'swim':
      doSwim(where, why)
   elif what == 'walk':
      doWalk(where, why)
   ...

现在你得到了一个新的方法"驱动":

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

但是等一下,有一个新的参数"车辆"——你以前不知道。现在您必须将它添加到mydo函数的签名中。

在这里,您可以将Kwargs投入使用——只需在签名中添加Kwargs即可:

1
2
3
4
5
def myDo(what, where, why, **kwargs):
   if what == 'drive':
      doDrive(where, why, **kwargs)
   elif what == 'swim':
      doSwim(where, why, **kwargs)

这样,您就不需要在每次调用的某些例程可能发生更改时更改接口函数的签名。

这只是一个很好的例子,你会发现Kwargs很有用。


基于一个好的示例有时比长的论述好,我将使用所有的python变量参数传递工具(位置参数和命名参数)编写两个函数。你应该能够很容易地看到它自己在做什么:

1
2
3
4
5
6
7
8
9
10
11
12
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)

下面是输出:

1
2
3
4
5
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})

motif:*args**kwargs用作需要传递给函数调用的参数的占位符。

使用*args**kwargs调用函数

1
2
3
4
def args_kwargs_test(arg1, arg2, arg3):
    print"arg1:", arg1
    print"arg2:", arg2
    print"arg3:", arg3

现在我们将使用*args调用上面定义的函数

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

结果:

ARG1:两个ARG2:3ARG3:5


现在,使用**kwargs调用相同的函数

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

结果:

ARG1:5ARG2:两个ARG3:3

底线:*args没有智能,它只是将传递的参数插入到参数中(从左到右顺序),而**kwargs通过在所需位置放置适当的值来智能地执行操作。


  • **kwargs中的kwargs只是变量名。你可以很好地喝一杯。
  • kwargs代表"关键字参数"。但我觉得最好把它们称为"命名参数",因为它们只是与名称一起传递的参数(在"关键字参数"一词中,"关键字"一词没有任何意义)。我想"关键字"通常是指编程语言保留的单词,因此程序员不能将其用于变量名。在禁运的情况下,这里不会发生这样的事情。所以我们命名param1param2传递给函数的两个参数值如下:func(param1="val1",param2="val2"),而不是只传递值:func(val1,val2)。因此,我认为它们应该被恰当地称为"任意数量的命名参数",因为如果func具有签名func(**kwargs)的话,我们可以指定任意数量的这些参数(即,参数)。

所以说,让我先解释"命名参数",然后再解释"命名参数的任意数量"kwargs

命名参数

  • 命名参数应位于位置参数之后
  • 命名参数的顺序不重要
  • 例子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    def function1(param1,param2="arg2",param3="arg3"):
        print("
    "
    +str(param1)+""+str(param2)+""+str(param3)+"
    "
    )

    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
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    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变量

因此,上述调用可以如下进行:

1
2
3
4
5
6
7
8
9
tupleCustomMargs="(自定义参数1""自定义参数2""自定义参数3")dictcustomnamedargs="customnamedparam1""val1""customnamedparam2""val2<div class="suo-content">[collapse title=""]<ul><li>我可以想象,<wyn>keyword</wyn>术语来自于您传入的dict,它是一个键值对的数据库。</li><li>你的意思是"key"-值对中的"key"字吗?它通常也不叫数据库,而是字典。但对关键词的使用仍然没有发现任何意义。</li></ul>[/collapse]</div><p><center>[wp_ad_camp_2]</center></p><hr><P>此外,您还可以在调用Kwargs函数时混合不同的使用方法:</P>[cc lang="python"]def test(**kwargs):
    print kwargs['a']
    print kwargs['b']
    print kwargs['c']


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

test( a=1, **args )

给出此输出:

1
2
3
1
2
3

注意,*kwargs必须是最后一个论点。


下面是一个简单的函数,用于解释用法:

1
2
3
4
5
def print_wrap(arg1, *args, **kwargs):
    print(arg1)
    print(args)
    print(kwargs)
    print(arg1, *args, **kwargs)

函数定义中未指定的任何参数将被放入args列表或kwargs列表中,具体取决于它们是否为关键字参数:

1
2
3
4
5
>>> print_wrap('one', 'two', 'three', end='blah', sep='--')
one
('two', 'three')
{'end': 'blah', 'sep': '--'}
one--two--threeblah

如果添加一个从未传递给函数的关键字参数,将引发一个错误:

1
2
>>> print_wrap('blah', dead_arg='anything')
TypeError: 'dead_arg' is an invalid keyword argument for this function

Kwargs是一种将名称参数作为字典(对于func)传递或将字典作为命名参数(对于func)传递的语法甜头。


下面是一个我希望有帮助的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#! /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] )

当你运行程序时,你会得到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ 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

这里的关键是调用中命名参数的变量数转换为函数中的字典。