None & Truthiness

RoadmapsPython Backend

Overview

`None` is Python's single null value and its built-in sentinel value — it means 'no value', not zero, not empty, not false. It's a singleton: there is exactly one `None` object in a running process, which is why identity checks (`is None`) work and are preferred over equality checks (`== None`). Truthiness is a separate rule: every object in Python can be evaluated in a boolean context (an `if`, a `while`, a `bool(...)` call), and Python decides `True` or `False` for it even if it's not a boolean. Falsy values are `None`, `False`, `0`, `0.0`, and any empty collection (`""`, `[]`, `{}`, `set()`, `()`). Everything else is truthy — including `0.0001`, `"False"` (a non-empty string!), and `[None]` (a non-empty list containing None). The trap: `if not value:` treats `None`, `0`, and `""` identically. If your code needs to distinguish 'the field is missing' from 'the field was explicitly set to zero/empty', truthiness collapses that distinction and you must check `is None` instead. count = 0 if not count: print("no count provided") # WRONG — fires even when count really is 0 if count is None: print("no count provided") # correct — 0 is a valid count, only None means missing

Backend code constantly needs to tell 'the client didn't send this field' apart from 'the client sent a real but empty/zero value' — request bodies, query params, and DB NULLs all funnel through this exact distinction, and using truthiness instead of an explicit `is None` check is one of the most common silent-bug sources in request handling.

Where used: FastAPI: `Optional[int] = None` as the signal for 'query param not supplied', dict.get(key, None) and `if result is None:` after a lookup, SQLAlchemy: a NULL column deserializes to `None`, distinct from an empty string

Why learn this

Code walkthrough

def summarize(items=None):
    if items is None:
        items = []
    total = len(items)
    return f"{total} item(s)"

print(summarize())
print(summarize([]))
print(summarize([1, 2, 3]))

Focus: Watch how `items is None` (not `if not items:`) is the only check that correctly separates 'no argument was passed at all' from 'an empty list was passed on purpose' — both branches would otherwise collapse to the same `if not items:` path.

Common mistakes

Glossary

falsy
A value that evaluates to `False` in a boolean context even though it isn't the boolean `False` itself — `None`, `0`, `0.0`, `""`, `[]`, `{}`, `set()`. Example: `if not items:`
sentinel value
A special placeholder value used to signal 'nothing here' or 'not provided', distinct from any real data value. `None` is Python's built-in sentinel value. Example: `def get(self, key, default=None):`

Recall questions

Understanding checks

What does this print?

falsy truthy

An empty string `""` has length 0, so it's falsy. A string containing a single space `" "` has length 1 — it's non-empty, so it's truthy, even though it looks 'blank' to a human reading it.

This function is supposed to reject requests with no `page` parameter, but it also rejects `page=0`, which should be valid (the first page, zero-indexed). What's wrong?

`if not page:` is True for both `None` (missing) and `0` (a valid page value) — it uses truthiness where it needs an identity check. Fix: `if page is None:`.

Truthiness treats every falsy value the same. To distinguish 'absent' from 'present but zero', you must check identity against `None` specifically, not truthiness.

Practice tasks

Continue learning

Previous: Mutable vs immutable types

Next: None & truthiness

Next: try / except / else / finally

Return to Python Backend Roadmap