Never Use None for Missing Values Again (Do This Instead)
There’s a better, safer way to represent missing data in Python — here’s what you should use instead.

Using None
feels simple — until it silently breaks your logic.
Never Use None
for Missing Values Again (Do This Instead)
Let’s be honest.
We’ve all done this:
def get_user_email(user):
return user.get("email", None)
Seems harmless, right?
But if you’ve worked on a growing codebase or touched production data pipelines, you’ve likely seen how using None
for missing values can quietly snowball into a tangled mess of bugs, unreadable conditionals, and unclear intent.
It’s time to stop reaching for None
as your default missing value.
Here’s why — and what you should do instead.
The Problem with None
In Python, None
is meant to represent the absence of a value. That’s fine, but it’s also incredibly generic and ambiguous.
Is it missing?
if value is None:
# Maybe missing?
Or maybe it’s not set yet?
def __init__(self):
self.cache = None # Will be filled later
Or maybe it’s intentional?
def send_email(to=None):
if to is None:
to = "default@example.com"
This overloading of None
creates semantic confusion. As a result, you often find yourself writing conditionals that are defensive, unclear, or just plain wrong.
Use Sentinel Objects Instead
When you need to represent missing or placeholder values, don’t use None
.
Use a custom sentinel object.
MISSING = object()
Now, you can clearly check:
def get_user_email(user):
email = user.get("email", MISSING)
if email is MISSING:
# handle missing case
...
You’ve just made the intent crystal clear:
You’re not checking for None
, you’re checking if the key was ever there.
Why Sentinel Objects Rock
1. Explicit is better than implicit
Using a unique object as your sentinel value is Pythonic. It removes ambiguity and forces you (and your teammates) to think intentionally about what’s missing, why it’s missing, and how to handle it.
2. Avoids false positives
Unlike None
, a sentinel won’t collide with other "falsy" values like 0
, ''
, or False
.
if value is not MISSING:
do_something(value)
Clean. Precise. No surprises.
3. Easier to debug
When debugging or logging, you instantly know if a value is the sentinel. It’s unmistakable — because it’s yours.
How to Implement Sentinel Values Cleanly
Here’s a reusable pattern:
class _Missing:
def __repr__(self):
return "<MISSING>"
MISSING = _Missing()
You can even make it fancier:
class Sentinel:
def __init__(self, name):
self.name = name
def __repr__(self):
return f"<{self.name}>"
MISSING = Sentinel("MISSING")
UNSET = Sentinel("UNSET")
Now you have descriptive, unique placeholders for different types of absence.
Bonus: Use Ellipsis
as a Built-in Sentinel
Python has a built-in singleton called Ellipsis
, represented by ...
.
def do_something(config=...):
if config is ...:
raise ValueError("config is required")
This is a clever hack for certain situations — but it can be confusing unless you’re consistent about using it. Still, it’s better than overloading None
.
Real-World Use Cases
Optional Arguments in Functions
Instead of:
def connect(db=None):
db = db or get_default_db()
Use:
def connect(db=MISSING):
if db is MISSING:
db = get_default_db()
Now, you respect None
if someone explicitly passed it.
Data Validation
For APIs or form inputs, sentinel values can differentiate between:
- A value that’s missing entirely
- A value explicitly set to
null
/None
Which often carry different meanings.
Wrapping Up
Using None
everywhere may feel convenient, but it’s rarely the right tool for nuanced cases.
If your code needs to distinguish between:
- Not present
- Intentionally empty
- Explicitly null
Then None
won’t cut it.
Define your own sentinel objects
Be explicit about missing values
Clean up your conditionals
Pro Tip:
Sentinel objects are one of those advanced Python techniques that feel small but have a big impact on code clarity, especially in large systems or libraries.
So next time you’re tempted to write or None
…
👀 Think again.
If you enjoyed this, follow me for more Python best practices and dev insights.
Let’s write better code — together.
