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 time
def 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:35
time.sleep(10)
test_default_value() # 2025-09-30 17:00:35
time.sleep(10)
test_default_value() # 2025-09-30 17:00:35
期望
期望当然是希望 start_time 每次的默认值都是 datetime.datetime.now() 生成的最新时间。
现象
结果却是 start_time 始终保持第一次生成的时间不变,而不是每次生成当前的最新时间。
原因
默认参数只在函数定义时被计算一次,这个参数在函数被调用时不会被重新计算,所以导致后续运行的 start_time 始终没有再发生变化。
提前生成的时间
import datetime
import time
def 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:51
time.sleep(10)
test_default_value() # 2025-09-30 17:02:51
time.sleep(10)
test_default_value() # 2025-09-30 17:02:51
期望
期望当然是希望 start_time 每次的默认值都是 datetime.datetime.now() 生成的最新时间。
现象
结果却是 start_time 始终保持程序开始运行的时间,也即这个默认值在函数真正运行前就已经生成好了,而不是在函数运行时才生成。
原因
默认参数值在函数被定义时已经计算出来,而不是在函数运行时才开始计算,所以导致上面的时间不是函数运行的时间。
总结
当函数被定义时,默认参数的值只会被创建一次,并作为函数对象的属性保存,而不是每次调用函数时都重新创建(使用 id() 查看对象内存地址,可以验证默认参数是同一个对象)。
import datetime
import time
def test_default_value(start_time=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")):
print(id(start_time)) # 即使多次调用函数,此默认参数对象的内存地址始终不变
time.sleep(1)
start_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") # 重新赋值引用新的对象
print(id(start_time))
if __name__ == '__main__':
test_default_value()
time.sleep(10)
test_default_value()
# 2973852936000
# 2973852936560
# 2973852936000
# 2973852934000
更多推荐

所有评论(0)