The None Type
None is Python’s way of representing the absence of a value. It is not zero, not an empty string, and not False — it is a distinct object that specifically means “there is no value here.” None is the sole value of the built-in type NoneType.
None Is a Singleton
There is only ever one None object in a running Python program. No matter how many times None appears in your code, every reference points to the exact same object in memory.
a = None b = None print(a is b) # True -- both refer to the single, shared None object print(id(a) == id(b)) # True print(type(a)) # <class 'NoneType'>
Checking for None: Use is, Not ==
Because None is a singleton, the idiomatic and safest way to check for it is with the identity operator is (or is not), not the equality operator ==.
value = None
if value is None:
print("No value provided")
if value is not None:
print("This won't print")Functions Without a Return Value
Any function that does not explicitly execute a return statement (or that executes a bare return with no value) automatically returns None.
def greet(name):
print(f"Hello, {name}!")
# no explicit return statement
result = greet("Ada")
# Hello, Ada!
print(result) # None
print(result is None) # TrueNone as a Default Argument Sentinel
None is frequently used as a placeholder default value for a function parameter, signaling “no value was passed” so the function body can decide what to do. This pattern is also how you safely avoid one of Python’s most infamous gotchas: mutable default arguments.
# The classic bug: a mutable default argument is created ONCE,
# when the function is defined -- and then reused across every call!
def add_item_buggy(item, items=[]):
items.append(item)
return items
print(add_item_buggy("apple")) # ['apple']
print(add_item_buggy("banana")) # ['apple', 'banana'] <- surprise! Same list reused.
# The fix: use None as a sentinel, and create a fresh list inside the function
def add_item_fixed(item, items=None):
if items is None:
items = []
items.append(item)
return items
print(add_item_fixed("apple")) # ['apple']
print(add_item_fixed("banana")) # ['banana'] -- fresh list every time, as expectedOptional[X]: Typing None-or-Something
When you annotate a function or variable with type hints, Optional[X] (from the typing module) documents that a value may be either type X or None. It is shorthand for Union[X, None].
from typing import Optional
def find_user(user_id: int) -> Optional[str]:
"""Returns the username, or None if no user with that id exists."""
users = {1: "ada", 2: "grace"}
return users.get(user_id) # dict.get() returns None if the key is missing
username = find_user(3)
if username is not None:
print(f"Found: {username}")
else:
print("User not found")None at a Glance
Question | Answer |
|---|---|
Is None falsy? | Yes — |
Is None equal to 0 or ""? | No — |
How many None objects exist? | Exactly one, for the lifetime of the program (singleton). |
Correct way to check for it? |
|
What does a function with no return give back? |
|
Key Takeaways
Nonerepresents "no value" and is the only instance ofNoneType.It is a singleton — every
Nonein your program is the same object.Always check for it with
is None/is not None, never==.A function without an explicit
returnimplicitly returnsNone.Noneis the standard sentinel default for optional parameters, especially to avoid the mutable-default-argument bug.Optional[X](orX | Nonein 3.10+) documents that a value may beXorNone.