*args和**kwargs是什么意思?
def foo(x, y, *args):
def bar(x, y, **kwargs):
*args和**kwargs是什么意思?
def foo(x, y, *args):
def bar(x, y, **kwargs):
当前回答
给定一个有3项作为参数的函数
sum = lambda x, y, z: x + y + z
sum(1,2,3) # sum 3 items
sum([1,2,3]) # error, needs 3 items, not 1 list
x = [1,2,3][0]
y = [1,2,3][1]
z = [1,2,3][2]
sum(x,y,z) # ok
sum(*[1,2,3]) # ok, 1 list becomes 3 items
想象一下这个玩具有一个三角形、一个圆形和一个长方形的袋子。那个包不太合身。你需要打开袋子,取出这3件物品,现在它们就可以了。Python*运算符执行此解包过程。
其他回答
单*表示可以有任意数量的额外位置参数。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}
从Python文档中:
如果位置参数多于形式参数槽,则会引发TypeError异常,除非存在使用语法“*identifier”的形式参数;在这种情况下,该形参接收包含多余位置参数的元组(如果没有多余位置参数,则为空元组)。如果任何关键字参数与正式参数名称不对应,则会引发TypeError异常,除非存在使用语法“**标识符”的正式参数;在这种情况下,该形参接收包含多余关键字参数的字典(使用关键字作为关键字,将参数值作为对应值),如果没有多余关键字参数,则接收(新的)空字典。
在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 3.x使用打开包装**与字符串格式一起使用
与字符串格式一起使用
除了本主题中的答案之外,还有一个其他地方没有提到的细节。这扩展了Brad Solomon的答案
使用python str.format时,使用**解包也很有用。
这有点类似于使用python f-string f-string所做的操作,但增加了声明dict以保存变量的开销(f-string不需要dict)。
快速示例
## init vars
ddvars = dict()
ddcalc = dict()
pass
ddvars['fname'] = 'Huomer'
ddvars['lname'] = 'Huimpson'
ddvars['motto'] = 'I love donuts!'
ddvars['age'] = 33
pass
ddcalc['ydiff'] = 5
ddcalc['ycalc'] = ddvars['age'] + ddcalc['ydiff']
pass
vdemo = []
## ********************
## single unpack supported in py 2.7
vdemo.append('''
Hello {fname} {lname}!
Today you are {age} years old!
We love your motto "{motto}" and we agree with you!
'''.format(**ddvars))
pass
## ********************
## multiple unpack supported in py 3.x
vdemo.append('''
Hello {fname} {lname}!
In {ydiff} years you will be {ycalc} years old!
'''.format(**ddvars,**ddcalc))
pass
## ********************
print(vdemo[-1])
除了函数调用之外,*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')
完整的代码在这里