把陷阱去掉了,反倒踩进了新的陷阱?

开发 前端
相信很多人都知道,Python有一个默认参数陷阱。函数的默认参数不能使用可变类型,否则会导致运行结果跟你想的不一样。

相信很多人都知道,Python有一个默认参数陷阱。函数的默认参数不能使用可变类型,否则会导致运行结果跟你想的不一样。例如:

图片

这段代码运行的时候,如果传入了一个列表,那么就往列表里面添加青南和产品经理​并用逗号连接起来打印。如果没有传入参数,就打印青南,产品经理。看起来似乎没有问题。但如果你不带参数多运行几次,就会发现问题出来了:

图片

为什么每次不传入参数的时候,打印的结果都不一样?而且越来越长?这个原因我公众号以前已经讲过了,根本原因就在于默认参数user_list=[]​这里的默认值[]是在代码运行时(Runtime)启动的时候就初始化的,每次调用函数一直使用这同一个对象,并不是每次调用函数的时候初始化。

要解决这个问题也非常简单,默认参数使用不可变对象就可以了:

图片

最近,我在上古代码中开发新功能,看到有一段处理Exception的函数,默认参数就使用的字典。代码大概长成下面这样:

def construct_exception(param_dict={}, msg='', extra_msg=''):
"""下面是具体代码"""

于是我就顺手把它改了:

def construct_exception(param_dict=None, msg='', extra_msg=''):
if param_dict = None:
param_dict = {}
"""下面是具体代码"""

理论上讲,我这样改移除了一个隐患,并且对后面的具体代码来说,param_dict始终都是一个字典,应该没有什么问题才对。

结果不久以后,有人给我报Bug。我一看,不就是我改的这个函数报错了吗。一通分析函数调用栈,发现了问题的原因。

这个函数原来是这样写的:

def construct_exception(param_dict={}, msg='', extra_msg=''):
"""一些代码"""
if isinstance(param_dict, dict):
msg = extra_msg.format(**param_dict)
"""其他代码"""

而上古代码里面,调用这个函数的时候,有下面两种写法:

exception_msg = construct_exception(param_dict=None, msg='报错信息')

param_dict = {'code': 123, 'reason': '数据库读取错误'}
exception_msg = construct_exception(param_dict=param_dict, extra_msg='报错码是:{code}, 报错原因:{reason}')

当他用不到param_dict​参数的时候,他竟然主动传了个None​进去。这样一来,他传入的None​就会被我强制转换为空字典。于是代码就会走到extra_msg.format(**param_dict)里面。这个时候由于没有填充大括号中的参数,于是就报错了:

图片

这个新的bug解决起来也简单,再判断一下param_dict是不是空就可以了:

def construct_exception(param_dict={}, msg='', extra_msg=''):
"""一些代码"""
if param_dict and isinstance(param_dict, dict):
msg = extra_msg.format(**param_dict)
"""其他代码"""

这真的应验了那句话,当一段显然有问题的代码竟然正常运行的时候,你就不要去动他了,它可能处于负负得正的状态,这一改反而可能把它改错了。

责任编辑:武晓燕 来源: 未闻Code
相关推荐

2014-07-29 09:16:14

Fragment

2021-07-08 23:53:44

Go语言拷贝

2020-09-28 13:57:37

区块链ICOLibra

2023-02-16 12:06:12

2020-10-10 17:34:11

大数据IT技术

2018-09-30 15:37:07

数据库MySQLMyCat

2023-02-08 16:29:58

前后端开发

2021-03-01 15:52:14

开源开源软件陷阱

2010-07-28 13:31:10

Flex数据绑定

2010-10-27 11:04:01

招聘

2010-07-19 15:49:22

求职陷阱

2017-10-20 10:19:49

Kotlin语言陷阱

2019-07-10 09:12:20

程序员级别跳槽

2009-06-01 14:54:50

jpaapiJava

2019-09-11 10:09:00

Java虚拟机算法

2013-04-17 10:34:55

.NET大对象堆

2011-04-14 13:52:27

ArrayList

2010-10-22 15:45:49

无线互联

2023-06-26 00:03:55

Go语言类型

2023-06-01 07:37:48

级别事务调度
点赞
收藏

51CTO技术栈公众号