*args和**kwargs是什么意思?

def foo(x, y, *args):
def bar(x, y, **kwargs):

当前回答

带*Args和**kwargs的“无限”Args

*args和**kwargs只是向函数输入无限字符的一种方式,例如:


def print_all(*args, **kwargs):
    print(args) # print any number of arguments like: "print_all("foo", "bar")"
    print(kwargs.get("to_print")) # print the value of the keyworded argument "to_print"


# example:
print_all("Hello", "World", to_print="!")
# will print:
"""
('Hello', 'World')
!
"""

其他回答

还值得注意的是,在调用函数时也可以使用*和**。这是一个快捷方式,允许您直接使用列表/元组或字典将多个参数传递给函数。例如,如果您具有以下功能:

def foo(x,y,z):
    print("x=" + str(x))
    print("y=" + str(y))
    print("z=" + str(z))

您可以执行以下操作:

>>> mylist = [1,2,3]
>>> foo(*mylist)
x=1
y=2
z=3

>>> mydict = {'x':1,'y':2,'z':3}
>>> foo(**mydict)
x=1
y=2
z=3

>>> mytuple = (1, 2, 3)
>>> foo(*mytuple)
x=1
y=2
z=3

注意:mydict中的键必须与函数foo的参数完全相同。否则将抛出TypeError:

>>> mydict = {'x':1,'y':2,'z':3,'badnews':9}
>>> foo(**mydict)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() got an unexpected keyword argument 'badnews'

在Python 3.5中,您还可以在列表、字典、元组和集合显示(有时也称为文字)中使用此语法。参见PEP 488:其他解包概括。

>>> (0, *range(1, 4), 5, *range(6, 8))
(0, 1, 2, 3, 5, 6, 7)
>>> [0, *range(1, 4), 5, *range(6, 8)]
[0, 1, 2, 3, 5, 6, 7]
>>> {0, *range(1, 4), 5, *range(6, 8)}
{0, 1, 2, 3, 5, 6, 7}
>>> d = {'one': 1, 'two': 2, 'three': 3}
>>> e = {'six': 6, 'seven': 7}
>>> {'zero': 0, **d, 'five': 5, **e}
{'five': 5, 'seven': 7, 'two': 2, 'one': 1, 'three': 3, 'six': 6, 'zero': 0}

它还允许在单个函数调用中解包多个可迭代项。

>>> range(*[1, 10], *[2])
range(1, 10, 2)

(感谢mgilson提供PEP链接。)

*args是一个特殊的参数,可以将0个或多个(位置)参数作为元组。**kwargs是一个特殊的参数,可以将0个或多个(关键字)参数作为字典。

*在Python中,有两种参数位置参数和关键字参数:

*参数:

例如,*args可以采用0个或多个参数作为元组,如下所示:

           ↓
def test(*args):
    print(args)

test() # Here
test(1, 2, 3, 4) # Here
test((1, 2, 3, 4)) # Here
test(*(1, 2, 3, 4)) # Here

输出:

()
(1, 2, 3, 4)
((1, 2, 3, 4),)
(1, 2, 3, 4)

并且,当打印*参数时,将打印4个数字,不带括号和逗号:

def test(*args):
    print(*args) # Here
 
test(1, 2, 3, 4)

输出:

1 2 3 4

并且,args具有元组类型:

def test(*args):
    print(type(args)) # Here
 
test(1, 2, 3, 4)

输出:

<class 'tuple'>

但是,*参数没有类型:

def test(*args):
    print(type(*args)) # Here
 
test(1, 2, 3, 4)

输出(错误):

TypeError:type()需要1或3个参数

并且,正常参数可以放在*args之前,如下所示:

          ↓     ↓
def test(num1, num2, *args):
    print(num1, num2, args)
    
test(1, 2, 3, 4)

输出:

1 2 (3, 4)

但是,**kwargs不能放在*args之前,如下所示:

             ↓     
def test(**kwargs, *args):
    print(kwargs, args)
    
test(num1=1, num2=2, 3, 4)

输出(错误):

语法错误:无效语法

而且,正常参数不能放在*args之后,如下所示:

                 ↓     ↓
def test(*args, num1, num2):
    print(args, num1, num2)
    
test(1, 2, 3, 4)

输出(错误):

TypeError:test()缺少2个必需的仅关键字参数:“num1”和“num2”

但是,如果正常参数具有默认值,则可以将它们放在*args之后,如下所示:

                      ↓         ↓
def test(*args, num1=100, num2=None):
    print(args, num1, num2)
    
test(1, 2, num1=3, num2=4)

输出:

(1, 2) 3 4

此外,**kwargs可以放在*args之后,如下所示:

                    ↓
def test(*args, **kwargs):
    print(args, kwargs)
    
test(1, 2, num1=3, num2=4)

输出:

(1, 2) {'num1': 3, 'num2': 4}

**克瓦格斯:

例如,**kwargs可以使用0个或多个参数作为字典,如下所示:

             ↓
def test(**kwargs):
    print(kwargs)

test() # Here
test(name="John", age=27) # Here
test(**{"name": "John", "age": 27}) # Here

输出:

{}
{'name': 'John', 'age': 27}
{'name': 'John', 'age': 27}

并且,当打印*kwargs时,将打印两个键:

def test(**kwargs):
    print(*kwargs) # Here
 
test(name="John", age=27)

输出:

name age

并且,kwargs具有dict类型:

def test(**kwargs):
    print(type(kwargs)) # Here
 
test(name="John", age=27)

输出:

<class 'dict'>

但是,*kwargs和**kwargs没有类型:

def test(**kwargs):
    print(type(*kwargs)) # Here
 
test(name="John", age=27)
def test(**kwargs):
    print(type(**kwargs)) # Here
 
test(name="John", age=27)

输出(错误):

TypeError:type()需要1或3个参数

并且,正常参数可以放在**kwargs之前,如下所示:

          ↓     ↓
def test(num1, num2, **kwargs):
    print(num1, num2, kwargs)

test(1, 2, name="John", age=27)

输出:

1 2 {'name': 'John', 'age': 27}

此外,*args可以放在**kwargs之前,如下所示:

           ↓
def test(*args, **kwargs):
    print(args, kwargs)

test(1, 2, name="John", age=27)

输出:

(1, 2) {'name': 'John', 'age': 27}

并且,正常参数和*args不能放在**kwargs之后,如下所示:

                    ↓     ↓
def test(**kwargs, num1, num2):
    print(kwargs, num1, num2)

test(name="John", age=27, 1, 2)
                     ↓
def test(**kwargs, *args):
    print(kwargs, args)

test(name="John", age=27, 1, 2)

输出(错误):

语法错误:无效语法

对于*args和**kwargs:

实际上,您可以为*args和**kwargs使用其他名称,如下所示*args和**kwargs通常使用:

            ↓        ↓
def test(*banana, **orange):
    print(banana, orange)
    
test(1, 2, num1=3, num2=4)

输出:

(1, 2) {'num1': 3, 'num2': 4}

这个示例将帮助您立即记住Python中的*args、**kwargs甚至super和继承。

class base(object):
    def __init__(self, base_param):
        self.base_param = base_param


class child1(base): # inherited from base class
    def __init__(self, child_param, *args) # *args for non-keyword args
        self.child_param = child_param
        super(child1, self).__init__(*args) # call __init__ of the base class and initialize it with a NON-KEYWORD arg

class child2(base):
    def __init__(self, child_param, **kwargs):
        self.child_param = child_param
        super(child2, self).__init__(**kwargs) # call __init__ of the base class and initialize it with a KEYWORD arg

c1 = child1(1,0)
c2 = child2(1,base_param=0)
print c1.base_param # 0
print c1.child_param # 1
print c2.base_param # 0
print c2.child_param # 1

此表便于在函数构造和函数调用中使用*和**:

            In function construction         In function call
=======================================================================
          |  def f(*args):                 |  def f(a, b):
*args     |      for arg in args:          |      return a + b
          |          print(arg)            |  args = (1, 2)
          |  f(1, 2)                       |  f(*args)
----------|--------------------------------|---------------------------
          |  def f(a, b):                  |  def f(a, b):
**kwargs  |      return a + b              |      return a + b
          |  def g(**kwargs):              |  kwargs = dict(a=1, b=2)
          |      return f(**kwargs)        |  f(**kwargs)
          |  g(a=1, b=2)                   |
-----------------------------------------------------------------------

这真的只是用来概括洛林·霍希斯坦的答案,但我觉得它很有用。

相关地:在Python 3中扩展了星形/splat运算符的用法