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

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

当前回答

除了函数调用之外,*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())

此外,具有仅对该子类实例有意义的新属性的子类可以调用基类__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')

完整的代码在这里

其他回答

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

从Python文档中:

如果位置参数多于形式参数槽,则会引发TypeError异常,除非存在使用语法“*identifier”的形式参数;在这种情况下,该形参接收包含多余位置参数的元组(如果没有多余位置参数,则为空元组)。如果任何关键字参数与正式参数名称不对应,则会引发TypeError异常,除非存在使用语法“**标识符”的正式参数;在这种情况下,该形参接收包含多余关键字参数的字典(使用关键字作为关键字,将参数值作为对应值),如果没有多余关键字参数,则接收(新的)空字典。

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

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'

*args和**kwargs是一种常见的习惯用法,允许任意数量的函数参数,如Python文档中关于定义函数的更多章节所述。

*参数将以元组的形式提供所有函数参数:

def foo(*args):
    for a in args:
        print(a)        

foo(1)
# 1

foo(1,2,3)
# 1
# 2
# 3

**kwargs会给你所有关键字参数,但与作为字典的形式参数相对应的参数除外。

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

bar(name='one', age=27)
# name one
# age 27

这两种习惯用法都可以与普通参数混合使用,以允许使用一组固定参数和一些可变参数:

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

也可以使用其他方式:

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

obj = {'b':10, 'c':'lee'}

foo(100,**obj)
# 100 10 lee

*l习惯用法的另一个用法是在调用函数时打开参数列表。

def foo(bar, lee):
    print(bar, lee)

l = [1,2]

foo(*l)
# 1 2

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

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

例如,以下命令在python 3中有效,但在python 2中无效:

>>> x = [1, 2]
>>> [*x]
[1, 2]
>>> [*x, 3, 4]
[1, 2, 3, 4]

>>> x = {1:1, 2:2}
>>> x
{1: 1, 2: 2}
>>> {**x, 3:3, 4:4}
{1: 1, 2: 2, 3: 3, 4: 4}

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

注:

语义上用于传递关键字参数的Python dict是任意排序的。然而,在Python 3.6中,关键字参数保证记住插入顺序。“**kwargs中元素的顺序现在对应于关键字参数传递给函数的顺序。”-Python3.6中的新功能事实上,CPython 3.6中的所有dict都将记住插入顺序作为实现细节,这在Python 3.7中成为标准。

def foo(param1,*param2):是一个可以接受任意数量的*param2值的方法,def bar(param1,**param2):是一种方法,可以接受任意数量的带有*param2键的值param1是一个简单的参数。

例如,在Java中实现varargs的语法如下:

accessModifier methodName(datatype… arg) {
    // method body
}