面试Python语言与信息数据获取和机器学习

关于Pyhton默认参数的一些思考

2017-05-22  本文已影响22人  SHISHENGJIA

我们知道Python中函数的可选参数可以有默认值,但是该默认值不能是可变类型。下面以一个简单的例子简单说明一下。

class HauntedBus:
    """闹鬼的校车"""

    def __init__(self, passengers=[]):
        self.passengers = passengers

    def pick(self, name):
        """上车"""
        self.passengers.append(name)

    def drop(self, name):
        """下车"""
        self.passengers.remove(name)

bus1 = HauntedBus()
bus1.pick('Tom')
print(bus1.passengers)  # ['Tom']

bus2 = HauntedBus()  # ['Tom']
print(bus2.passengers)

bus2.pick('Jack')
print(bus2.passengers)  # ['Tom', 'Jack']

print(bus1.passengers is bus2.passengers)  # True

从结果中可以看出,登上bus1的乘客Tom出现在了bus2中。
问题在于,没有指定初始乘客的 HauntedBus 实例会共享同一个乘客列表。
这是因为不为 HauntedBus 指定乘客的话self.passengers 变成了 passengers 参数默认值(即[])的别名,而这个问题的根源在于默认值在定义函数时计算(通常在加载模块时),就已经变成了函数对象的属性。因此,如果默认值是可变对象,而且修改了它的值,那么后续的函数调用都会受到影响。
可变默认值导致的这个问题说明了为什么通常使用 None 作为接收可变值的参数的默认值。
下面修改上面例子中的部分问题代码。

def __init__(self, passengers=None):
    if passengers is None:
        self.passengers = []
    else:
        self.passengers = list(passengers)

在这个代码中,如果构造实例时没有传入参数,那么会新建一个空列表赋值给self.passengers,另外值得注意的是,如果参数passengers不为None,我们将参数值的副本list(passengers)赋值给了self.passengers。这是因为如果直接将passengers赋值给self.passengers的话,那么在self.passengers上直接调用remove()或者append()方法的话,其实会修改传给构造方法的那个列表。

上一篇下一篇

猜你喜欢

热点阅读