最近遇到一个非常诡异的bug,最终结果还蛮有趣的。代码大体如下:
def fetch(url, method='GET', headers={}, data=None):
if data is not None:
headers['Content-Length'] = len(data)
method = 'POST'
build_request(url, method, headers, data)
#...
乍一看,并没有什么特别的,而bug也是偶现的,经过大量的反复实验,发现一个POST请求之后,同样的域名再发送一个GET请求时,目标服务器无返回了。抓包后发现,GET请求时莫名地多一个Content-Length的头,而值好像是随机。
原来函数的默认值是一个固定的不会被释放的对象,比如:
def run(d = {}):
d[time.time()] = 1
print(d)
该例子不传参数时,每次运行,d都会多一个值。
这就理解为什么很多人写的代码里,会有这么两种风格,第一种是全用None为默认参数:
def run(d = None):
d = d or {}
第二种是拷贝后删除原引用,绝对禁止向参数中插入数据:
def run(d = {}):
another_d = {**d}
del d