2.2.2 默认参数

Python 的函数可以有默认值,这个功能很好用:

def foo(a, l=[]):
    l.append(a)
    return l

foo(2,[1])  # 给数组 [1] 添加一个元素 2,得到 [1,2]
foo(2)      # 没有传入数组,使用默认的空数组,得到 [2]

然而如果这样调用:

foo(2)  # 利用默认参数,得到 [2]
foo(3)  # 竟然得到了 [2, 3]

函数调用了两次以后,默认参数被改变了,也就是说函数调用产生了副作用。这是因为默认参数的存储并不像函数里的临时变量一样存储在栈上、随着函数调用结束而释放,而是存储在函数这个对象的内部:

foo.__defaults__  # 一开始确实是空数组
foo(2)  # 利用默认参数,得到 [2]
foo.__defaults__  # 如果打印出来看,已经变成 [2] 了
foo(3)  # 再添加一个元素就得到了 [2, 3]

因为函数 foo 作为一个对象,不会被释放,因此这个对象内部的属性也不会随着多次调用而自动重置,会一直保持上次发生的变化。基于这个前提,我们得出一个结论:函数的默认参数不允许是可变对象,比如这里的 foo 函数需要这么写:

def foo(a, l=None):
    if l is None:
        l = []
    l.append(a)
    return l

print(foo(2)) # 得到 [2]
print(foo(3)) # 得到 [3]

现在,给参数添加默认值的行为在函数体中完成,不会随着函数的多次调用而累积。

对于 Python 的默认参数来说:

如果默认值是不可变的,可以直接设置默认值,否则要设置为 None 并在函数体中设置默认值。

Last updated