python 遇到的小坑

时间:2021-04-25 14:25:44

由于前端资源紧缺,我的后端系统迟迟等不来它的前端,没办法只好自己来写了。从html,js入门学起,然后照着vue.js的官方教程写了几个实例,从github上clone了一个不错的vue.js模版,填充了一个星期。虽然界面有些丑,但是总算是走通了全部的业务,期间被跨域,跳转,cookie等问题折磨得不要不要的。有时间的话,本螺旋手里剑会总结vue.js开发过程中遇到的问题。

言归正传,本周博主基本没碰python代码,只是修复了一个bug,这个bug很有意思。bug描述为:本次请求的返回结果中总是携带着之前请求的结果,重启服务后bug暂时修复,稍后又会出现。第一感觉是数据库缓存问题,但是我们没有对mysql启用特殊的缓存机制,所以不是缓存问题。第二感觉是执行相关的sql操作之后,结果是否commit立即生效,经过排查commit生效了,也不是这个问题。那就只好debug代码了,最后一个定位到了一个方法的传参问题。

展示问题代码的简化版本

#!/usr/bin/python
# -*- coding: utf-8 -*- class TEST(object):
def test(self, info, info_list=[]):
info_list.append(info)
return info_list if __name__ == '__main__':
a = TEST()
print a.test(1)
print a.test(2)
print a.test(3)

相信大部分人和我对输出的预期是一样的,在写代码时,我认为输出结果是

[1]
[2]
[3]

但是实际的输出结果是

[1]
[1, 2]
[1, 2, 3]

看来bug找到了,之前请求的info都保留在了这次请求的返回结果中。重启服务之后,info_list被重新初始化成[],所以bug短暂的消失了。问题找到了,但是为什么会产生这种问题呢。当我们实例化这个方法时,info_list被初始化为[],之后不会被再次初始化。可以理解为info_list在该方法中是一个全局变量,想修改它的值,只能在调用方法时传入一个新的info_list对其覆盖,也就是说将方法调用修改为a.test(1, [])就不会存在这种问题。并不是所有的数据结构都存在这个问题,只有list、dict这种可变的数据结构才会有这种问题,tuple、string、int等都不存在这个问题。所以说,以后在方法中对list、dict做初始化时建议使用以下风格。

#!/usr/bin/python
# -*- coding: utf-8 -*- class TEST(object):
def test(self, info, info_list=None):
if info_list is None:
info_list = []
info_list.append(info)
return info_list if __name__ == '__main__':
a = TEST()
print a.test(1)
print a.test(2)
print a.test(3)

输出结果符合预期

[1]
[2]
[3]