协慌网

登录 贡献 社区

**(双星 / 星号)和 *(星号 / 星号)对参数有什么作用?

在以下方法定义中, ***param2做了什么?

def foo(param1, *param2):
def bar(param1, **param2):

答案

*args**kwargs是允许任意数量的函数参数的常用习惯用法,如更多关于在 Python 文档中定义函数的部分所述。

*args将为您提供所有函数参数作为元组

In [1]: def foo(*args):
   ...:     for a in args:
   ...:         print a
   ...:         
   ...:         

In [2]: foo(1)
1


In [4]: foo(1,2,3)
1
2
3

**kwargs将为您提供所有关键字参数,除了与形式参数相对应的字典。

In [5]: def bar(**kwargs):
   ...:     for a in kwargs:
   ...:         print a, kwargs[a]
   ...:         
   ...:         

In [6]: bar(name='one', age=27)
age 27
name one

这两个习语都可以与普通参数混合,以允许一组固定和一些变量参数:

def foo(kind, *args, **kwargs):
   pass

*l习惯用法的另一个用法是在调用函数时解包参数列表

In [9]: def foo(bar, lee):
   ...:     print bar, lee
   ...:     
   ...:     

In [10]: l = [1,2]

In [11]: foo(*l)
1 2

在 Python 3 中,可以在赋值( Extended Iterable Unpacking )的左侧使用*l ,尽管在此上下文中它给出了一个列表而不是一个元组:

first, *rest = [1,2,3,4]
first, *l, last = [1,2,3,4]

Python 3 也增加了新的语义(参考PEP 3102 ):

def func(arg1, arg2, arg3, *, kwarg1, kwarg2):
    pass

这样的函数只接受 3 个位置参数, *之后的所有内容只能作为关键字参数传递。

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

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'

单 * 表示可以有任意数量的额外位置参数。 foo()可以像foo(1,2,3,4,5)一样调用。在 foo()的主体中,param2 是一个包含 2-5 的序列。

双 ** 表示可以有任意数量的额外命名参数。 bar()可以像bar(1, a=2, b=3)一样调用。在 bar()的主体中,param2 是一个包含 {'a':2,'b':3} 的字典

使用以下代码:

def foo(param1, *param2):
    print param1
    print param2

def bar(param1, **param2):
    print param1
    print param2

foo(1,2,3,4,5)
bar(1,a=2,b=3)

输出是

1
(2, 3, 4, 5)
1
{'a': 2, 'b': 3}