在Python中,默认参数只在函数定义时计算一次,而不是在每次调用时。这意味着,如果默认参数使用的是可变对象(例如列表或字典),那么在没有明确指定该参数的所有函数调用中,这个对象都是共享的。
示例:
def append_item(item, items=[]): items.append(item) return items print(append_item(1)) # [1] print(append_item(2)) # [1, 2],而预期是 [2]
正确的方法:
def append_item(item, items=None): if items is None: items = [] items.append(item) return items
现在每次调用都会获得自己的列表。
问题: 使用默认可变对象多次调用函数会发生什么?
回答: 每次都在修改同一个对象。上面的示例说明了这一点——列表会累积所有值。
故事 在一个大型Web应用中,缓存数据时使用了一个带有默认字典参数的函数。这导致数据在不同用户之间“泄漏”:某人更改了自己的个人资料——这些更改有时会显示给其他用户,因为全局字典的共享状态。
故事 在测试中使用了一个带有可变默认列表的函数来收集状态。一个测试的数据“流入”另一个,导致意外崩溃,无法重现错误并且调试困难。
故事 在一个用于聚合日志的微服务中,通过一个默认参数是列表的函数来积累事件。日志重复出现——旧请求的临时积累落到了新客户端,导致需要几个小时的调查和数据丢失。