Sentinel values are a fundamental but under-documented part of Python’s design. They are used to represent absence, unsupported operations, incomplete state, and to coordinate control flow between objects. Yet, they are often treated as ad-hoc implementation details.
This talk starts by clarifying what sentinel values are and why None is frequently semantically overloaded and incorrect for modelling “missing” or “unset” values. We then examine built-in sentinels such as NotImplemented, Ellipsis, and dataclasses.MISSING, with a detailed look at how NotImplemented enables double dispatch in equality and ordering operations.
The second half of the talk focuses on typing, where sentinel values expose fundamental tensions between Python’s dynamic semantics and static type systems. We will discuss:
To ground this in practice, we will look at real-world patterns used in production code, including Pydantic’s experimental missing concept, and explain the trade-offs these designs make.
Finally, we will examine PEP 661, the proposal to standardize sentinel values and their typing semantics. We will explain what it would solve, why it was deferred, and what that deferral means for library and API authors today.
The talk concludes with concrete, honest guidelines: when sentinel values are the right tool, how to design APIs around them, and how to communicate absence clearly in typed Python code without pretending the type system can do more than it currently can.