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

作者: SHISHENGJIA | 来源:发表于2017-05-22 16:07 被阅读22次

    我们知道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()方法的话,其实会修改传给构造方法的那个列表。

    相关文章

      网友评论

        本文标题:关于Pyhton默认参数的一些思考

        本文链接:https://www.haomeiwen.com/subject/razbxxtx.html