要了解发生了什么,请考虑以下案例:
>>> def test1(**d):
... print(d)
>>> test1(spam=10)
{'spam': 10}
{'spam': 10} 是从哪里来的?很简单:**d 只是将所有与任何命名参数不匹配的关键字参数(无论它们来自何处)打包到一个新的字典中,并将该字典作为d 提供给您。
现在看** 在参数方面:
>>> def test2(spam, eggs):
... print(spam, eggs)
>>> d = {'eggs': 10, 'spam': 20}
>>> test2(**d)
20 10
因此 Python 将 **d 扩展为一组单独的关键字参数,它们与参数的匹配方式与实际单独的关键字参数完全相同。
最后,两边:
>>> def test3(spam, eggs, **d):
... print(spam, eggs)
... print(d)
>>> d = {'spam': 10, 'cheese': 20}
>>> test3(eggs=30, **d)
10 30
{'cheese': 20}
因此 Python 将 **d 参数扩展为两个单独的关键字参数,将它们与普通关键字参数 eggs=30 放在一起,将它们与参数 spam 和 eggs 匹配,并将任何剩余部分存储在**d 参数中的新字典。
the tutorial 对此进行了粗略的解释,the reference 对此进行了更严格的解释。
事实上,你在定义上有一个**d 参数并在调用上有一个**d 参数这一事实并没有什么特别之处;它们不必以任何方式相互对应。
有些人认为不幸的是,Python 对定义中的可变参数参数和调用中的参数解包使用相同的语法,并且对定义中的默认参数值和调用中的关键字参数使用相同的语法。但是,虽然当你第一次遇到它时会感到困惑,但一旦你理解了,它就很容易记住和阅读。其他用 ...args 与 seq... 等语法区分两者的语言最初似乎并没有减少混淆。