Python中默认对象何时创建?函数参数默认值初始化疑问
现象原因
Python的函数默认参数是在**函数定义阶段(模块加载时)**就完成初始化并绑定的,而非函数调用阶段。
当你在util_script.py中定义def migrate_entity(project, name, access=AccessClass.AccessClass())时,只要util_script模块被主脚本导入(哪怕主脚本没调用migrate_entity,比如执行./main_script.py -h或提前quit()),Python解释器就会在加载util_script模块时,执行AccessClass.AccessClass()创建实例,并将这个实例绑定为access参数的默认值,自然会触发AccessClass.__init__方法。
为什么改为None就正常?
当你把默认值设为None时,None是Python的内置不可变常量,模块加载时只是将access的默认值绑定到这个常量的引用。而函数内部的if access is None: access = AccessClass.AccessClass()逻辑,是在函数被调用时才执行的,只有真正调用migrate_entity且未传入access参数时,才会创建AccessClass实例,避免了模块加载阶段的提前初始化。
参数默认值是否总是提前创建?
是的,Python中所有函数的默认参数都会在函数定义时完成初始化绑定,这是Python的设计特性,并非bug。
需要注意的是,对于不可变对象(如int、str、None),这种提前绑定通常不会引发问题;但对于可变对象(如列表、字典、自定义类实例),就会出现“默认值被复用”的意外行为,比如:
def add_item(lst=[]): lst.append("item") print(lst) add_item() # 输出: ['item'] add_item() # 输出: ['item', 'item'],两次调用共用同一个列表实例
正确的实现方式
对于需要动态创建的可变默认参数,标准做法是将默认值设为None,并在函数内部初始化:
def migrate_entity(project, name, access=None): if access is None: access = AccessClass.AccessClass() # 函数核心逻辑
内容的提问来源于stack exchange,提问作者Sven

