在 Python 中,'None' 经常被当作“瑞士军刀”来表示值缺失、发生错误或配置未设置。然而,这种多功能性造成了语义上的歧义。例如,在缓存系统中,返回值为 'None' 可能意味着键在字典中缺失,也可能意味着键存在但被明确映射为 'None'。同样,在配置更新中,'timeout=None' 参数根据具体实现的不同,可能被解释为“无超时”或“保留现有值”。为了解决这些冲突,开发者可以使用哨兵值——这些是存在于有效数据域之外的唯一对象,确保它们永远不会与实际值重叠。

Python 的标准库已经利用了几个内置的哨兵值来管理复杂的行为。'Ellipsis' (...) 对象用于在 NumPy 切片中跳过维度,而 'NotImplemented' 则作为信号,指示在其他地方寻找实现,从而为二元运算符提供“双重分派”功能。最近,Pydantic 库引入了 'MISSING' 哨兵,用于区分从未发送的字段和被明确设置为 null 的字段。在历史上,开发者使用 'object()' 创建自定义哨兵,但这种方法经常破坏 MyPy 等工具中的静态类型收窄。虽然使用 'Literal' 字符串或 'Enum' 技巧等变通方法很常见,但它们往往在身份检查或序列化(pickling)方面存在权衡。

随着 PEP 661 的通过,Python 3.15 引入了专门的内置 'sentinel' 来标准化这一模式。这允许类型检查器像处理 'None' 一样收窄类型。例如,现在一个函数可以检查参数是否恰好是 'sentinel' 值,以确定是否应跳过操作,同时仍允许 'None' 表示有效的“空”状态。虽然新的内置对象为 API 设计提供了更清晰的路径,但旧版本的开发者可以使用 'typing_extensions' 进行回移植。向正式哨兵的转变突显了 Python 向更精确语义的转变,即从过度使用的 'None' 转向对缺失状态的显式、类型安全表示。