应使用None作默认参数并在函数内调用工厂函数生成新对象,避免可变默认参数陷阱;因默认参数在定义时求值一次,直接写func(x=[])会导致多次调用共享同一对象。
func(x = [])
Python 中默认参数在函数定义时就求值一次,不是每次调用时新建。所以 def f(x = []) 的 [] 是同一个列表对象,多次调用会累积修改——这是经典陷阱。工厂函数本身不解决这个问题,除非你让它“延迟执行”。
None 作占位符 + 函数内调用工厂把默认值设为 None,在函数体里判断并调用工厂函数生成新对象。这是最清晰、最易读、兼容所有 Python 版本的方式。
示例:
def create_item(items=None):
if items is None:
items = list() # 或 lambda: [], 或其他工厂逻辑
items.append("new")
return items
list()、dict()、MyClass(),也可以是自定义函数如 lambda: [0] * 3
is [] 或 == [] 判断,默认值是 None 才可靠如果你大量函数都需要这种行为,可以抽象一层,但别过早优化。简单场景下,硬编码 if x is None: x = factory() 更直白、调试更友好。
装饰器示例(仅作参考,非推荐首选):
def lazy_default(**factories):
def decorator(func):
def wrapper(**kwargs):
for k, factory in factories.items():
if k not in kwargs or kwargs[k] is None:
kwargs[k] = factory()

return func(**kwargs)
return wrapper
return decorator
@lazy_default(items=lambda: [])
def process(items):
items.append("done")
return items
items=None 才触发工厂functools.partial 模拟工厂默认值有人试图写 def f(x=partial(list)),这是错的——partial 对象本身不是可调用的“结果”,而是一个待绑定的对象;你得手动 x() 才能拿到新列表,这破坏了函数签名语义。
partial(list) 不等于 list(),前者是构造器,后者是调用结果x: list = partial(list))会失效,mypy 会报错真正需要每次新建,默认值必须延迟到函数体内执行。最安全的路径就是守住 None 占位 + 显式工厂调用这条线。其它包装方案在多数项目里只是增加认知负担。