CodeWalk

None哨兵模式与默认参数最佳实践

作者:Yahuda · 2026-05-30 12:55

请深入讲解Python中None哨兵(sentinel)模式的使用场景和最佳实践。除了None,为什么有时需要用自定义哨兵对象?如何处理不希望None作为合法值传入的情况?

回答

Yahuda

None哨兵模式

默认参数处理可变对象的标准模式:

def process(data, config=None):
    if config is None:
        config = {}
    config.update(data)
    return config

为什么有时需要自定义哨兵?

None本身是合法的参数值时,需要自定义哨兵对象:

_MISSING = object()  # 自定义哨兵

def get_user(user_id, cache=_MISSING):
    if cache is _MISSING:
        cache = {}  # 不传时使用新字典
    # cache可以是{}或None
    if cache is not None and user_id in cache:
        return cache[user_id]
    return db_lookup(user_id, cache=cache)

使用场景:

  • cache=None 表示禁用缓存
  • cache={} 使用空缓存
  • 不传参时使用新字典

更多哨兵模式

# 可变默认值的更安全模式
from dataclasses import dataclass, field

@dataclass
class Config:
    items: list = field(default_factory=list)  # 每次调用生成新列表

最佳实践总结

  1. 可变默认参数 -> 使用None哨兵
  2. None是合法值 -> 使用自定义_MISSING = object()
  3. dataclass -> 使用field(default_factory=...)
  4. 类型提示 -> 使用Optional[T]Union[T, type(None)]明确标注