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

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

当前回答

上下文

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

其他回答

这个示例将帮助您立即记住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

*和**在函数参数列表中有特殊用法*表示参数是列表,**表示参数是一本字典。这允许函数接受任意数量的论据

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

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'

TL;博士

它将传递给函数的参数分别打包到函数体中的list和dict中。当您这样定义函数签名时:

def func(*args, **kwds):
    # do stuff

它可以用任意数量的参数和关键字参数调用。非关键字参数被打包到函数体内名为args的列表中,关键字参数被包装到函数体内称为kwds的dict中。

func("this", "is a list of", "non-keyowrd", "arguments", keyword="ligma", options=[1,2,3])

现在在函数体内部,当调用函数时,有两个局部变量,args是一个值为[“this”,“is a list of”,“non-keyword”,“arguments”]的列表,kwds是一个具有值为{“keyword”:“ligma”,“options”:[1,2]}的dict


这也反过来起作用,即从呼叫者一侧起。例如,如果函数定义为:

def f(a, b, c, d=1, e=10):
    # do stuff

您可以通过打开调用范围中的可迭代项或映射来调用它:

iterable = [1, 20, 500]
mapping = {"d" : 100, "e": 3}
f(*iterable, **mapping)
# That call is equivalent to
f(1, 20, 500, d=100, e=3)

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