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

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • importUIKit classViewController:UITabBarController{ enumD...
    明哥_Young阅读 9,452评论 1 10
  • Hello Word 在屏幕上打印“Hello, world”,可以用一行代码实现: 你不需要为了输入输出或者字符...
    restkuan阅读 8,436评论 0 6
  • 1 “小张,给你个任务,写一篇报道,就围绕催婚这个话题。” 就这样,我接到了杂志社工作以来的第一个任务,还是当下最...
    古拉巴什之王阅读 2,801评论 0 2
  • 今天新学的内容是函数,因为都在一个主函数操作会使程序显得很乱,所以利用设置函数,在主函数调用,来实现一种功能,既能...
    庞爽阅读 838评论 0 0
  • 3109103-陈求忠总结,《2017年11月30号》(连续总结第4天)辅导员-海燕姐 一:今天完成目标 1抄写p...
    进阶阶段阅读 1,319评论 0 0