上古代码漫游记(二):把陷阱去掉了,反倒踩进了新的陷阱?

简介: 上古代码漫游记(二):把陷阱去掉了,反倒踩进了新的陷阱?


摄影:产品经理炸牛奶



两个月之前,我写了一篇文章《长见识,让大家看看什么是垃圾代码》,不少同学都表示长见识了。今天我们再来看另外一个问题。

相信很多人都知道,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 is 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=None, msg='', extra_msg=''):
    """省略前面的代码"""
    if param_dict and isinstance(param_dict, dict):
        msg = extra_msg.format(**param_dict)
    """其他代码"""

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

目录
相关文章
|
Web App开发 编解码 Ubuntu
YouTube下载视频教程:常用的网站软件插件APP都有涉及
有时候可能需要YouTube上的视频来进行一些操作,比如教程演示,语言学习,视频编辑等.....那么YouTube视频怎么下载下来呢?方法比较多。在这篇文章里我会给大家介绍一些下载YouTube视频的常用网站、浏览器插件、电脑软件和手机APP,方便大家找到最合适的方法去保存油管视频。
2931 1
YouTube下载视频教程:常用的网站软件插件APP都有涉及
|
前端开发
websocket的心跳机制
websocket的心跳机制
1101 3
|
8月前
|
机器学习/深度学习 算法 PyTorch
PyTorch 实现MobileNetV1用于图像分类
本实验基于PyTorch和昇腾平台,详细讲解了如何使用MobileNetV1模型对CIFAR10数据集进行图像分类。内容涵盖MobileNetV1的特点、网络架构剖析(尤其是深度可分离卷积)、代码实现及训练过程。通过该实验,读者可以掌握轻量级CNN模型在移动端或嵌入式设备中的应用,并了解其在资源受限环境下的高效表现。实验包括数据预处理、模型训练与测试等环节,帮助用户快速上手并优化模型性能。
266 53
|
5月前
|
存储 人工智能 自然语言处理
又双叒叕获认可!阿里云AI Stack一体机首批通过国家评测认证
近日,阿里云AI Stack一体机通过了中国电子技术标准研究院的“云上部署DeepSeek验证测试”,成为首批通过该评测的AI大模型一体机。
554 10
|
11月前
|
JavaScript API 图形学
(在线查看三维模型)在线CAD中创建三维建筑墙体
本文详细介绍如何使用mxcad3d创建建筑墙体模型。首先需安装Node.js及npm包管理器,并通过npm初始化项目、引入mxcad包。接着,在项目中编写HTML与TypeScript代码以实现墙体绘制,包括外墙、内墙、窗户和门的创建。最后,通过运行项目验证效果。教程及完整项目示例可在[mxcad3d官方仓库](https://gitee.com/mxcadx/mxcad_docs/tree/master/examples3D/Test3dWall.7z)获取。更多详细步骤,请关注“梦想云图网页CAD”公众号。
|
传感器 安全 大数据
|
机器学习/深度学习 监控 安全
现货量化合约跟单/交易所系统开发成熟技术/案例搭建/玩法详情/步骤指南
现货量化合约跟单系统开发是指构建一个系统,通过使用量化交易策略,实现将现货市场的交易信号自动化地应用到交易合约中,以进行自动化的跟单交易。 以下是现货量化合约跟单系统开发的关键概述:
|
消息中间件 关系型数据库 Kafka
实时计算 Flink版操作报错之在执行任务时遇到了一个IO错误,具体表现为无法从本地主机(localhost)下载文件,该怎么解决
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
|
Linux 数据处理 开发者
Linux命令ldd:深入解析动态链接器依赖关系
`ldd`是Linux下分析可执行文件动态依赖的工具,它揭示了程序运行所需的共享库。通过模拟动态链接过程,`ldd`列出库文件路径,帮助理解程序环境和解决运行时问题。主要参数包括`-d`、`-r`、`-u`和`-v`。例如,`ldd my_program`展示`my_program`的依赖关系。注意,`ldd`不显示间接依赖,完整依赖树可能需借助其他工具。确保系统库完整且版本兼容是使用`ldd`时的关键。
|
存储 Ubuntu Linux
linux系统中rootfs根文件系统制作及挂载基本操作
linux系统中rootfs根文件系统制作及挂载基本操作
2835 1