Python 默认参数和参数名称
我在想,'a=a'和'b=b'这样的写法会不会导致问题或者出现意想不到的情况?在这个例子中,代码运行得很好。
def add_func(a=2,b=3):
return a+b
a=4
b=5
answer = add_func(a=a, b=b)
谢谢
2 个回答
这要看你指向的全局对象是可变的还是不可变的。不可变对象,比如整数,修改的时候会生成一个副本,所以这样做是安全的。而可变对象,比如列表,修改的时候是在原地进行的,这样做就不安全了。对它们的任何修改都会在调用之间保留,可能会导致意想不到的行为(而且很可能会发生)。
这个:
a=[]
def f(a=a):
pass
和这个是一样的:
def f(a=[]):
pass
在Python程序中,这是一种众所周知的坏习惯。
我不知道有没有这样的情况,不过我很乐意被证明是错的。
正式的语言参考文档定义了函数调用的结构。其中一个重要的部分是,它把“关键字参数”定义为 标识符 "=" 表达式
。接下来,它还说明了如何理解函数调用中的参数:
如果有关键字参数,首先会把它们转换为位置参数,具体步骤如下。首先,会为正式参数创建一个未填充的槽位列表。如果有 N 个位置参数,它们会放在前 N 个槽位中。接着,对于每个关键字参数,会用标识符来确定对应的槽位(如果标识符和第一个正式参数的名字相同,就用第一个槽位,以此类推)。如果槽位已经被填满,就会抛出一个类型错误(TypeError)。否则,参数的值会放入这个槽位中,填满它(即使这个值是 None,也会填满槽位)。当所有参数都处理完后,仍然未填充的槽位会用函数定义中的默认值来填充。
这列出了一些可能的情况。
在你提到的简单情况下,比如有两个正式参数(a
和 b
),如果你用关键字参数来调用函数,比如 add_func(a=a, b=b)
,会发生以下事情:
- 会创建两个槽位来存放参数。
- 因为你在调用中没有提供任何位置参数(只有关键字参数),所以最开始这些槽位都是空的。
- 每个关键字参数会被单独分析,你的参数的标识符(这里的“a”在
a=
这部分)会和函数的所有正式参数名进行比较(这些参数名是在定义函数时给的,在我们的例子中是a
和b
)。 - 当找到匹配时,关键字参数的值(在这个例子中是
4
!)会用来填充对应的槽位。 - 这个过程会一直重复,直到所有的关键字参数都被分析。如果还有槽位没有被填满,Python 会尝试给剩下的槽位分配一个默认值(如果有的话)。如果没有,就会抛出一个错误。
所以,Python 对关键字参数中的“标识符”的处理方式是完全不同的。不过,这种情况只适用于关键字参数;显然,如果你尝试像 add_func(b, a)
这样调用,即使你的参数本身叫 b
和 a
,这也不会和函数中的正式参数对应;你的参数顺序会搞错。但是,add_func(b=b, a=a)
这样调用是没问题的;只要是关键字参数,位置就不重要。