提问



在以下方法定义中,***param2的作用是什么?


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

最佳参考


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


*args将为您提供所有函数参数作为元组:[131]


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,尽管它在此上下文中给出了列表而不是元组:[132]


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


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


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


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

其它参考1


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


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'

其它参考2


单*表示可以有任意数量的额外位置参数。 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}

其它参考3



  

**(双星)和*(星)为参数做什么




它们允许函数定义为接受用户传递任意数量的参数,位置(*)和关键字(**) 。


定义函数



*args允许任意数量的可选位置参数(参数),这些参数将被分配给名为args的元组。


**kwargs允许任意数量的可选关键字参数(参数),这些参数将位于名为kwargs的dict中。


您可以(并且应该)选择任何适当的名称,但如果目的是使参数具有非特定语义,则argskwargs是标准名称。


扩展,传递任意数量的参数



您还可以使用*args**kwargs分别从列表(或任何可迭代)和dicts(或任何映射)传入参数。


接收参数的函数不必知道它们正在被扩展。


例如,Python 2的xrange没有明确地期望*args,但是因为它需要3个整数作为参数:


>>> x = xrange(3) # create our *args - an iterable of 3 integers
>>> xrange(*x)    # expand here
xrange(0, 2, 2)


另一个例子,我们可以在str.format中使用dict扩展:


>>> foo = 'FOO'
>>> bar = 'BAR'
>>> 'this is foo, {foo} and bar, {bar}'.format(**locals())
'this is foo, FOO and bar, BAR'


Python 3中的新功能:使用仅关键字参数

定义函数

你可以在*args之后只有关键字参数 - 例如,这里,kwarg2必须作为关键字参数给出 - 而不是位置:[134]


def foo(arg, kwarg=None, *args, kwarg2=None, **kwargs): 
    return arg, kwarg, args, kwarg2, kwargs


用法:


>>> foo(1,2,3,4,5,kwarg2='kwarg2', bar='bar', baz='baz')
(1, 2, (3, 4, 5), 'kwarg2', {'bar': 'bar', 'baz': 'baz'})


此外,*可以单独用于指示仅关键字参数,而不允许无限制的位置参数。


def foo(arg, kwarg=None, *, kwarg2=None, **kwargs): 
    return arg, kwarg, kwarg2, kwargs


这里,kwarg2必须是一个显式命名的关键字参数:


>>> foo(1,2,kwarg2='kwarg2', foo='foo', bar='bar')
(1, 2, 'kwarg2', {'foo': 'foo', 'bar': 'bar'})


而且我们不能再接受无限制的位置论证,因为我们没有*args*:


>>> foo(1,2,3,4,5, kwarg2='kwarg2', foo='foo', bar='bar')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() takes from 1 to 2 positional arguments 
    but 5 positional arguments (and 1 keyword-only argument) were given


同样,更简单地说,这里我们要求kwarg通过名称给出,而不是按位置给出:


def bar(*, kwarg=None): 
    return kwarg


在这个例子中,我们看到如果我们尝试在位置上传递kwarg,我们会得到一个错误:


>>> bar('kwarg')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: bar() takes 0 positional arguments but 1 was given


我们必须显式传递kwarg参数作为关键字参数。


>>> bar(kwarg='kwarg')
'kwarg'


Python 2兼容演示



*args(通常说star-args)和**kwargs(可以通过说kwargs暗示星星,但明确表示双星kwargs)是Python使用的常用习语***符号。这些特定的变量名称并不是必需的(例如,您可以使用*foos**bars),但偏离惯例可能会激怒您的Python同事。


当我们不知道我们的函数将要接收什么或者我们可能传递多少个参数时,我们通常会使用这些,有时即使分别命名每个变量也会变得非常混乱和多余(但这种情况通常是明确的比隐含更好。


示例1


以下函数描述了它们的使用方式,并演示了行为。请注意,命名b参数将在第二个位置参数之前使用:


def foo(a, b=10, *args, **kwargs):
    '''
    this function takes required argument a, not required keyword argument b
    and any number of unknown positional arguments and keyword arguments after
    '''
    print('a is a required argument, and its value is {0}'.format(a))
    print('b not required, its default value is 10, actual value: {0}'.format(b))
    # we can inspect the unknown arguments we were passed:
    #  - args:
    print('args is of type {0} and length {1}'.format(type(args), len(args)))
    for arg in args:
        print('unknown arg: {0}'.format(arg))
    #  - kwargs:
    print('kwargs is of type {0} and length {1}'.format(type(kwargs),
                                                        len(kwargs)))
    for kw, arg in kwargs.items():
        print('unknown kwarg - kw: {0}, arg: {1}'.format(kw, arg))
    # But we don't have to know anything about them 
    # to pass them to other functions.
    print('Args or kwargs can be passed without knowing what they are.')
    # max can take two or more positional args: max(a, b, c...)
    print('e.g. max(a, b, *args) \n{0}'.format(
      max(a, b, *args))) 
    kweg = 'dict({0})'.format( # named args same as unknown kwargs
      ', '.join('{k}={v}'.format(k=k, v=v) 
                             for k, v in sorted(kwargs.items())))
    print('e.g. dict(**kwargs) (same as {kweg}) returns: \n{0}'.format(
      dict(**kwargs), kweg=kweg))


我们可以通过help(foo)检查函数签名的在线帮助,它告诉我们


foo(a, b=10, *args, **kwargs)


让我们用foo(1, 2, 3, 4, e=5, f=6, g=7)调用这个函数


打印:


a is a required argument, and its value is 1
b not required, its default value is 10, actual value: 2
args is of type <type 'tuple'> and length 2
unknown arg: 3
unknown arg: 4
kwargs is of type <type 'dict'> and length 3
unknown kwarg - kw: e, arg: 5
unknown kwarg - kw: g, arg: 7
unknown kwarg - kw: f, arg: 6
Args or kwargs can be passed without knowing what they are.
e.g. max(a, b, *args) 
4
e.g. dict(**kwargs) (same as dict(e=5, f=6, g=7)) returns: 
{'e': 5, 'g': 7, 'f': 6}


示例2


我们也可以使用另一个函数调用它,我们只提供a:


def bar(a):
    b, c, d, e, f = 2, 3, 4, 5, 6
    # dumping every local variable into foo as a keyword argument 
    # by expanding the locals dict:
    foo(**locals()) 


bar(100)打印:


a is a required argument, and its value is 100
b not required, its default value is 10, actual value: 2
args is of type <type 'tuple'> and length 0
kwargs is of type <type 'dict'> and length 4
unknown kwarg - kw: c, arg: 3
unknown kwarg - kw: e, arg: 5
unknown kwarg - kw: d, arg: 4
unknown kwarg - kw: f, arg: 6
Args or kwargs can be passed without knowing what they are.
e.g. max(a, b, *args) 
100
e.g. dict(**kwargs) (same as dict(c=3, d=4, e=5, f=6)) returns: 
{'c': 3, 'e': 5, 'd': 4, 'f': 6}


示例3:装饰器中的实际用法


好吧,也许我们还没有看到实用程序。所以想象一下,在区分代码之前和/或之后你有多个带有冗余代码的函数。以下命名函数只是用于说明目的的伪代码。


def foo(a, b, c, d=0, e=100):
    # imagine this is much more code than a simple function call
    preprocess() 
    differentiating_process_foo(a,b,c,d,e)
    # imagine this is much more code than a simple function call
    postprocess()

def bar(a, b, c=None, d=0, e=100, f=None):
    preprocess()
    differentiating_process_bar(a,b,c,d,e,f)
    postprocess()

def baz(a, b, c, d, e, f):
    ... and so on


我们可能能够以不同的方式处理这个问题,但我们当然可以使用装饰器提取冗余,因此下面的示例演示了*args**kwargs如何非常有用:


def decorator(function):
    '''function to wrap other functions with a pre- and postprocess'''
    @functools.wraps(function) # applies module, name, and docstring to wrapper
    def wrapper(*args, **kwargs):
        # again, imagine this is complicated, but we only write it once!
        preprocess()
        function(*args, **kwargs)
        postprocess()
    return wrapper


现在,每个包装的函数都可以更简洁地编写,因为我们已经考虑了冗余:


@decorator
def foo(a, b, c, d=0, e=100):
    differentiating_process_foo(a,b,c,d,e)

@decorator
def bar(a, b, c=None, d=0, e=100, f=None):
    differentiating_process_bar(a,b,c,d,e,f)

@decorator
def baz(a, b, c=None, d=0, e=100, f=None, g=None):
    differentiating_process_baz(a,b,c,d,e,f, g)

@decorator
def quux(a, b, c=None, d=0, e=100, f=None, g=None, h=None):
    differentiating_process_quux(a,b,c,d,e,f,g,h)


通过分解*args**kwargs允许我们执行的代码,我们减少了代码行数,提高了可读性和可维护性,并为程序中的逻辑提供了唯一的规范位置。如果我们需要改变这个结构的任何部分,我们有一个地方可以进行每次更改。

其它参考4


让我们首先了解什么是位置参数和关键字参数。
以下是使用位置参数的函数定义示例。


def test(a,b,c):
     print(a)
     print(b)
     print(c)

test(1,2,3)
#output:
1
2
3


所以这是一个带位置参数的函数定义。
您也可以使用关键字/命名参数调用它:


def test(a,b,c):
     print(a)
     print(b)
     print(c)

test(a=1,b=2,c=3)
#output:
1
2
3


现在让我们用关键字参数来研究函数定义的示例:


def test(a=0,b=0,c=0):
     print(a)
     print(b)
     print(c)
     print('-------------------------')

test(a=1,b=2,c=3)
#output :
1
2
3
-------------------------


您也可以使用位置参数调用此函数:


def test(a=0,b=0,c=0):
    print(a)
    print(b)
    print(c)
    print('-------------------------')

test(1,2,3)
# output :
1
2
3
---------------------------------


所以我们现在知道具有位置和关键字参数的函数定义。


现在让我们研究*运算符和**运算符。


请注意,这些运营商可以在两个方面使用:


a)函数调用


b)功能定义


函数调用中使用*运算符和**运算符。


让我们直接举一个例子然后讨论它。


def sum(a,b):  #receive args from function calls as sum(1,2) or sum(a=1,b=2)
    print(a+b)

my_tuple = (1,2)
my_list = [1,2]
my_dict = {'a':1,'b':2}

# Let us unpack data structure of list or tuple or dict into arguments with help of '*' operator
sum(*my_tuple)   # becomes same as sum(1,2) after unpacking my_tuple with '*'
sum(*my_list)    # becomes same as sum(1,2) after unpacking my_list with  '*'
sum(**my_dict)   # becomes same as sum(a=1,b=2) after unpacking by '**' 

# output is 3 in all three calls to sum function.


所以记住


函数调用中使用*或**运算符时 -


*运算符将数据结构(如列表或元组)解包为函数定义所需的参数。


**运算符将字典解包为函数定义所需的参数。


现在让我们研究函数定义中的*运算符。
例:


def sum(*args): #pack the received positional args into data structure of tuple. after applying '*' - def sum((1,2,3,4))
    sum = 0
    for a in args:
        sum+=a
    print(sum)

sum(1,2,3,4)  #positional args sent to function sum
#output:
10


在函数定义中,*运算符将接收的参数打包到元组中。


现在让我们看一下函数定义中使用的**的示例:


def sum(**args): #pack keyword args into datastructure of dict after applying '**' - def sum({a:1,b:2,c:3,d:4})
    sum=0
    for k,v in args.items():
        sum+=v
    print(sum)

sum(a=1,b=2,c=3,d=4) #positional args sent to function sum


在函数定义中,**运算符将接收的参数打包到字典中。


所以请记住:


函数调用中,元组的*解包数据结构或列表将被函数定义接收到的位置或关键字参数。


函数调用中,将字典的**解包数据结构转换为函数定义接收的位置或关键字参数。


函数定义中,将*打包位置参数转换为元组。


函数定义中,将**打包关键字参数放入字典中。

其它参考5


***在函数参数列表中有特殊用法。 *
暗示该参数是一个列表,**暗示该参数
是一本字典。这允许函数采用任意数量的
参数

其它参考6


从Python文档:



  如果存在比正式参数槽更多的位置参数,则会引发TypeError异常,除非存在使用语法* identifier的形式参数;在这种情况下,该形式参数接收包含多余位置参数的元组(或者如果没有多余的位置参数则为空元组)。

  
  如果任何关键字参数与形式参数名称不对应,则引发TypeError异常,除非存在使用语法** identifier的形式参数;在这种情况下,该形式参数接收包含多余关键字参数的字典(使用关键字作为键,参数值作为对应值),或者如果没有多余的关键字参数则接收(新)空字典。


其它参考7


我想举一个其他人没有提到过的例子


*还可以解压生成器


Python3文档中的一个示例


x = [1, 2, 3]
y = [4, 5, 6]

unzip_x, unzip_y = zip(*zip(x, y))


unzip_x将是[[1,2,3]],unzip_y将是[[4,5,6]]


zip()接收多个iretable args,并返回一个生成器。


zip(*zip(x,y)) -> zip((1, 4), (2, 5), (3, 6))

其它参考8


在Python 3.5中,您还可以在listdicttupleset显示(有时也称为文字)中使用此语法。参见PEP 488:其他拆包概括。[135]


>>> (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链接。)

其它参考9


虽然在Python 3中扩展了对星/splat运算符的使用,但我喜欢下表,因为它与这些运算符与函数的使用有关。 splat运算符可以在函数构造和函数调用中使用:[136] [137]


            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)                   |
-----------------------------------------------------------------------


这真的只是总结了Lorin Hochstein的答案,但我觉得它很有帮助。

其它参考10


除了函数调用之外,* args和** kwargs在类层次结构中也很有用,也避免了在Python中编写__init__方法。在类似Django代码的框架中可以看到类似的用法。


例如,


def __init__(self, *args, **kwargs):
    for attribute_name, value in zip(self._expected_attributes, args):
        setattr(self, attribute_name, value)
        if kwargs.has_key(attribute_name):
            kwargs.pop(attribute_name)

    for attribute_name in kwargs.viewkeys():
        setattr(self, attribute_name, kwargs[attribute_name])


那么子类就可以了


class RetailItem(Item):
    _expected_attributes = Item._expected_attributes + ['name', 'price', 'category', 'country_of_origin']

class FoodItem(RetailItem):
    _expected_attributes = RetailItem._expected_attributes +  ['expiry_date']


然后将子类实例化为


food_item = FoodItem(name = 'Jam', 
                     price = 12.0, 
                     category = 'Foods', 
                     country_of_origin = 'US', 
                     expiry_date = datetime.datetime.now())


此外,具有仅对该子类实例有意义的新属性的子类可以调用Base类__init__来卸载属性设置。
这是通过* args和** kwargs完成的。 kwargs主要用于使用命名参数可读取代码。例如,


class ElectronicAccessories(RetailItem):
    _expected_attributes = RetailItem._expected_attributes +  ['specifications']
    # Depend on args and kwargs to populate the data as needed.
    def __init__(self, specifications = None, *args, **kwargs):
        self.specifications = specifications  # Rest of attributes will make sense to parent class.
        super(ElectronicAccessories, self).__init__(*args, **kwargs)


可以实例化为


usb_key = ElectronicAccessories(name = 'Sandisk', 
                                price = '$6.00', 
                                category = 'Electronics',
                                country_of_origin = 'CN',
                                specifications = '4GB USB 2.0/USB 3.0')


完整的代码在这里[139]

其它参考11


对于那些通过例子学习的人:


def f(normal_input, *args, **kw):
    # Print the length of args and kw in a friendly format
    print("len(args) = {} and len(kw) = {}".format(len(args), len(kw)))

l = list(range(5))
d = {"k0":"v0", "k1":"v1"}

f(42, 0, 1, 2, 3, 4, 5) # len(args) = 6 and len(kw) = 0

f(42, l) # len(args) = 1 and len(kw) = 0
f(42, d) # len(args) = 1 and len(kw) = 0

f(42, *l) # len(args) = 5 and len(kw) = 0
f(42, *d) # len(args) = 2 and len(kw) = 0

try:
    f(42, **l) # Gives an error
except TypeError:
    print("l in f(**l) is not a dictionary!")

f(42, **d) # len(args) = 0 and len(kw) = 2

# Without explicitly feeding normal_input
# l[0] becomes normal_input
f(*l) # len(args) = 4 and len(kw) = 0

# Let's try everything now
f(42, 420, 4200, *l, **d) # len(args) = 7 and len(kw) = 2


请注意,第一个参数是normal_input,第二个,第三个和* l是接下来的7个参数。

其它参考12


在函数中使用两者的一个很好的例子是:


>>> def foo(*arg,**kwargs):
...     print arg
...     print kwargs
>>>
>>> a = (1, 2, 3)
>>> b = {'aa': 11, 'bb': 22}
>>>
>>>
>>> foo(*a,**b)
(1, 2, 3)
{'aa': 11, 'bb': 22}
>>>
>>>
>>> foo(a,**b) 
((1, 2, 3),)
{'aa': 11, 'bb': 22}
>>>
>>>
>>> foo(a,b) 
((1, 2, 3), {'aa': 11, 'bb': 22})
{}
>>>
>>>
>>> foo(a,*b)
((1, 2, 3), 'aa', 'bb')
{}

其它参考13


这个例子可以帮助你立刻记住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

其它参考14


* args=* aList =列表中的所有元素


** args=** aDict=dict中的所有项目

其它参考15


*args**kwargs:允许您将可变数量的参数传递给函数。


*args:用于向函数发送非keyworded变长参数列表:


def args(normal_arg, *argv):
    print ("normal argument:",normal_arg)

    for arg in argv:
        print("Argument in list of arguments from *argv:", arg)

args('animals','fish','duck','bird')


会产生:


normal argument: animals
Argument in list of arguments from *argv: fish
Argument in list of arguments from *argv: duck
Argument in list of arguments from *argv: bird


**kwargs*


**kwargs允许您将keyworded可变长度的参数传递给函数。如果要在函数中处理命名参数,则应使用**kwargs


def who(**kwargs):
    if kwargs is not None:
        for key, value in kwargs.items():
            print ("Your %s is %s." %(key,value))

who (name="Nikola", last_name="Tesla", birthday = "7.10.1856", birthplace = "Croatia")  


会产生:


Your name is Nikola.
Your last_name is Tesla.
Your birthday is 7.10.1856.
Your birthplace is Croatia.