使用可选的可变参数定义函数

使用具有可变默认类型的可选参数时出现问题(在使用可选参数定义函数中进行了描述 ),这可能会导致意外行为。 ****

说明

这个问题是因为一个函数的默认参数初始化一旦被该功能时,在点定义,并不能 (像许多其他语言)当函数被称为。默认值存储在函数对象的 __defaults__ 成员变量中。

def f(a, b=42, c=[]):
    pass

print(f.__defaults__)
# Out: (42, [])

对于不可变类型(参见 Argument 传递和可变性 ),这不是问题,因为没有办法改变变量; 它只能被重新分配,保持原始值不变。因此,后续保证具有相同的默认值。但是,对于可变类型,通过调用其各种成员函数,原始值可以变异。因此,不保证对函数的连续调用具有初始缺省值。

def append(elem, to=[]):
    to.append(elem)      # This call to append() mutates the default variable "to"
    return to

append(1)
# Out: [1]

append(2)  # Appends it to the internally stored list
# Out: [1, 2]

append(3, [])  # Using a new created list gives the expected result
# Out: [3]

# Calling it again without argument will append to the internally stored list again
append(4)   
# Out: [1, 2, 4]

注意: 某些 IDE(如 PyCharm)会在将可变类型指定为默认属性时发出警告。

如果要确保默认参数始终是你在函数定义中指定的参数,那么解决方案是始终使用不可变类型作为默认参数。

当需要使用可变类型作为默认值时,实现此目的的常用习惯是使用 None(不可变)作为默认参数,然后如果它等于 None 则将实际默认值分配给参数变量。

def append(elem, to=None):
    if to is None:
        to = []

    to.append(elem)
    return to