python中创建一个空列表使用什么函数_Python实验室:千万别把函数默认值设为「」,这个错误你犯过吗?...

前言

在Python的函数定义中,我们可以给函数形参指定一个默认值,这样,在函数使用时,如果默认值已满足我们的需求,我们就可以略过该参数;如果不满足,我们也可以指定其他值,这样可以使设计的函数兼顾易用性与灵活性。但在Python中有一点需要注意,千万不要以 '[]' 作为参数默认值。

529f5d030794dc5f9503486810cb3c7f.png

探索

为什么不能将 '[]' 作为函数默认值呢?我们从一个简单的例子开始:

5d58153f3cff82d313702b4ea21017fe.png

运行结果:

[5]

[5, 5]

[5, 5, 5]

三次调用func(),期望的结果是每次都返回一个[5],但实际上返回的列表中5的个数逐次增多。这样的结果表明,似乎有个列表被缓存在函数中,每次调用的时候都会对这个列表进行操作。

我们在调用中间插入一些指定参数值的调用,看看结果如何:

07a867ea165cead20522d63ae542237a.png

运行结果:

[5]

[5, 5]

[5, 5, 5]

[5]

[5, 5, 5, 5]

从结果看出,对于指定参数值的调用,返回的结果与期望的一致,但是在再次使用默认值时,又出现同样的情况。

我们进一步分析返回的结果:

bb1cc58ba07571a231fb5b2b98094c12.png

运行结果:

2929752624712

2929752624712

2929752624712

2929752567624

2929752624712

从以上结果可以看出,对于所有使用默认值的情形,操作和返回的都是同一个列表,并没有每次调用函数时创建一个新列表作为默认值,这也就可以解释为什么返回列表中的值越来越多。

那这个神秘的列表缓存到哪了呢?

d01bf832ef3c7d82a6e4710725448dcf.png

运行结果:

([],)

([5],)

([5, 5],)

1863704923720

1863704923720

从以上结果可以看出,作为默认值的列表实际上被缓存在函数func的属性__default__中,__default__是一个元组,会缓存所有函数参数的默认值。

那默认值列表是什么时候创建出来的呢?

参数默认值实际上是Python解析器第一次解析语句 def func(input = [])的时候创建的,这个过程实际上会创建一个函数对象,同时设置函数对象的__default__属性,以后每次以默认值调用函数时就修改__default__属性中缓存的值。

'[]' 既然不应该作为函数的默认值,那我们应该如何修改函数实现以达到同样的目标呢?参考如下实现:

962f33cbb6b49e9ffc80d31933dc4a6f.png

运行结果:

[5]

[5]

推荐的做法是:以None作为默认参数,在函数体内对输入参数进行检查,在input为None时创建空列表并使用。

对于面向对象编程,还有一个类似但比较隐晦的例子:

3fb50fe6fd464bcaf17da019fdfe5a78.png

运行结果:

2330464706440

[]

[]

[5]

[5]

2330464706440

2330464706440

当我们以一个空列表作为类的__init__函数的形参默认值时,如果在创建对象时使用默认参数值,那么这个列表将在所有以默认值创建的对象间共享。另外,第一行的结果实际表明,即使在类还没有任何对象的时候,函数的默认值列表已经被创建并被缓存在函数__init__中,这个过程与函数默认值一致。

总结

  • 我们在编码时千万不要以 '[]' 作为函数参数的默认值,除非你非常清楚这里发生的情况是你所期望的。
  • 函数的默认值会以引用的形式缓存于函数的__defaults__属性中。
  • 本文虽以 '[]' 贯穿全文,但实际上对于可变变量都存在同样的问题,读者需要留心。

如果您觉得此文对您有帮助,请转发给更多的人,并点击右上角「关注」按钮,了解更多博文更新。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值