Python 之可变参数作为默认值的坑
当然,官方肯定建议是不要用可变参数作为函数的默认值,但是奈何肯定有很多犟牛,偏偏不信邪,然后就出现了很多奇奇怪怪的预期之外的现象。
不断变长的列表
最经典的案例当属下面这种不断变长的列表。
def test_default_value(item=["hello"]):print(item)item.append("world")if __name__ == '__main__':test_default_value() # ['hello']test_default_value() # ['hello', 'world']test_default_value() # ['hello', 'world', 'world']
期望
期望当然是希望 item 每次的默认值都是给定的 ["hello"] 。
现象
结果确是后面的运行中,item 使用了前面的运行结果,导致 item 越来越长。
原因
程序会调用定义函数时保存的默认参数,并在上一次的基础上进行操作叠加,即列表在 append 的时候会在 item 原来的基础上 append 追加值,所以导致列表越来越长。
永不变化的时间
import datetime
import timedef test_default_value(start_time=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")):print(start_time)if __name__ == '__main__':test_default_value() # 2025-09-30 17:00:35time.sleep(10)test_default_value() # 2025-09-30 17:00:35time.sleep(10)test_default_value() # 2025-09-30 17:00:35
期望
期望当然是希望 start_time 每次的默认值都是 datetime.datetime.now() 生成的最新时间。
现象
结果却是 start_time 始终保持第一次生成的时间不变,而不是每次生成当前的最新时间。
原因
默认参数只在函数定义时被计算一次,这个参数在函数被调用时不会被重新计算,所以导致后续运行的 start_time 始终没有再发生变化。
提前生成的时间
import datetime
import timedef test_default_value(start_time=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")):print(start_time)if __name__ == '__main__':print(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")) # 2025-09-30 17:02:51time.sleep(10)test_default_value() # 2025-09-30 17:02:51time.sleep(10)test_default_value() # 2025-09-30 17:02:51
期望
期望当然是希望 start_time 每次的默认值都是 datetime.datetime.now() 生成的最新时间。
现象
结果却是 start_time 始终保持程序开始运行的时间,也即这个默认值在函数真正运行前就已经生成好了,而不是在函数运行时才生成。
原因
默认参数值在函数被定义时已经计算出来,而不是在函数运行时才开始计算,所以导致上面的时间不是函数运行的时间。