昨天调一个统计函数差点把我整崩溃。代码大概长这样:
简单说
def add_item(x, buf=[]):
buf.append(x)
return buf
第一次 add_item(1) 返回 [1],看着没毛病。第二次 add_item(2) 居然吐出 [1, 2],我当场愣住。查了半天才反应过来:buf=[] 不是在每次调用时新建的,而是在 def 那一刻就创建好一个对象,之后所有调用共用同一个 list,append 全累积到同一块内存上去了。
这坑最恶心的地方是不报错也不 warning,就 quietly 把状态串了。要命的是它只在被多次调用时才暴露,单元测试往往只跑一次,根本测不出来。其实
正确姿势是用 None 当哨兵,在函数体里再初始化:
def add_item(x, buf=None):
buf = buf or []
buf.append(x)
return buf
记住一条:默认参数只求值一次。可变对象(list/dict/set)别直接当默认值,跨调用的静默共享迟早咬你一口 (´・_・`)