Python Null (None): Guide to Missing Values and NoneType

Kimberly FesselKimberly Fessel

Python Null Explained

If you could give nothing a name, what would you call it? Many programming languages, including SQL, Java, and C#, call it “.” You may have also encountered null pointers or null references in other languages.

In Python, null is called None. It’s easy enough to create, but you’ll need special to check for None.

We’ll cover those operators in this article, along with its common uses, best practices, and “gotchas,” so you won’t be left None the wiser about what’s going on.

What is “Null” in Python?

Null traditionally represents missing information or the absence of a value. Think of null more like a concept than a specific value. It signals that a value is missing, unavailable, or intentionally absent. Python labels missing values with the keyword None. It’s a falsy Python object but not equivalent to other falsy values like the empty string, zero, or a blank list. You’ll see None as a default , as a return value from functions, within collection-like , and on its own.

None in Python: Defining Null Objects and Its Data Type

You assign None in Python using its built-in keyword:

python
x = Noneprint(x) # Expected result:# None

Remember to capitalize None, since Python is case sensitive. Also note that None is a NoneType:

python
type(x) # Expected result:# <class 'NoneType'>

This shows that None has the type NoneType. Python creates the None object for you, you won’t need to instantiate it yourself.

None is a , meaning Python creates only one None object in memory. Every variable assigned to None references the same object:

python
a = Noneb = Noneprint(a is b) # Expected result:# True

We assign a and b to None, which refers to the same memory object; this is why a is b returns True.

Checking for None: is Operator and Comparisons

Once you have Python’s null value floating around in your code, the next logical step is checking for it, especially in . The recommended way to check for None relies on the is identity operator:

python
x = Noneif x is None:    print("x is None")# Expected result:# x is None

Likewise, the compound operator is not lets you do a negative check:

python
if x is not None:    print("x has a value")

The identity operator (is) is preferred over the equality operator (==) when checking for null in Python. The is operator checks object identity, meaning it determines whether two variables reference the exact same object in memory. == can work for None, but it’s not guaranteed to behave consistently across custom objects. None represents the absence of a value, not a value that needs to be compared. Because of this, we don’t care about equivalence. We care about whether a variable points to None, a singleton object. Using is None makes that intent explicit and avoids any edge cases where equality behavior could be customized.

As a rule: use is / is not for None, and reserve == for value comparisons.

The Most Common Uses of None

Now that you know how to create and check for None in Python, let’s explore some of the typical places None appears.

None as a Default Parameter for Function Arguments

Perhaps the most common way to use None is as a default value for a . Parameters show up in parentheses just after the function’s name in its definition, and you may give them a default value following the pattern of variable_name = default_value. If you don’t provide an argument value for an optional parameter when calling the function, Python uses the default.

Here’s an example function to greet the user. If no function argument is provided for name, the parameter defaults to None, and the function prints a generic greeting:

python
def greet(name=None):    if name is None:        print("Hi there!")    else:        print(f"Hi, {name}!")greet(name="Sarah")greet()# Expected result:# Hi, Sarah!# Hi there!

Better than falling back on an empty string, using None as the default for an optional function argument lets you detect when a value was omitted and handle that case separately inside the function.

None as the Default Return Value

Every Python function returns a value, even if you don’t explicitly program it to do so. Consider the code for this simple greeter that has no return statement:

python
def greet_simple():    print("Hi there!")output = greet_simple()print(output)# Expected result:# Hi there!# None

The function prints a greeting but doesn’t include a return statement, so Python returns None by default. You can verify that by checking that output has the type NoneType:

python
print(type(output)) # Expected result:# <class 'NoneType'>

A function whose primary purpose is a side effect like printing, writing to a file, creating a data visualization, and so on often returns None. Python also returns None when a function contains a return statement without a value. Because None is the default return value, you’ll often encounter it when working with functions that don’t explicitly return anything.

None Values in Data Structures

None can also appear as a valid element inside collections such as lists and dictionaries, where it often represents a placeholder for missing data. For example, this list contains a mix of user names and unknown values:

python
users = ["Sarah", None, "Mike", "Kiki", None]print(users) # Expected result:# ['Sarah', None, 'Mike', 'Kiki', None]

You’ll also see None as dictionary values. (It’s also a valid key, but that’s less common.) Here, user has a phone field, but no phone number has been provided:

python
user = {    "name": "Sarah",    "subscription": "Pro",    "phone": None}print(user["phone"])# Expected result:# None

Because None is a regular Python object, you can store it in collections just like strings, numbers, and other values.

None vs NaN in Python

If you’ve ventured into the world of NumPy or pandas, you’ve likely encountered NaN, which stands for “not a number.” It’s tempting to draw parallels between None and NaN, since both feel “null-like” and are associated with missing or unknown values. There are, however, some major distinctions to keep in mind.

Feature

None

NaN

Definition

Absence of a value

Invalid/undefined numeric value

Type

NoneType

float

Usage

General purpose

Numerical/analytical workflows

Comparison

Use is

Use math.isnan()

The following code demonstrates NaN in Python through the built-in math library:

python
x = float('nan')print(x)print(type(x))print(math.isnan(x))# Expected result:# nan# <class 'float'># True

But here’s the biggest NaN gotcha:

python
print(float('nan') == float('nan'))# Expected result:# False

Unlike None, a NaN value is not considered equal to itself, making functions like math.isnan() absolutely critical for detection.

Handling Missing Values: Best Practices

Entire books have been written about best practices when handling null values, but we’ll keep it brief. As your skills with Python’s null value, None, increase, here are some ways you can level up your code.

None in Type Hints

Unlike other programming languages like C and Java, Python its variables, meaning you don’t need to declare each kind of variable you create. This boosts coding speed but can lead to confusion later, especially in user-defined Python functions.

introduced in Python 3.5 (2015), improves readability and debugging. You can use type hints to define the expected input and output types of a function. For instance, this greeter anticipates one input, name, which is a string, and returns None:

python
def greet_string(name: str) -> None:    print(f"Hi, {name}!")greet_string("Sarah")# Expected result:# Hi, Sarah!

As shown earlier, None often serves as a default value:

python
def greet(name=None):    if name is None:        print("Hi there!")    else:        print(f"Hi, {name}!")greet()# Expected result:# Hi there!

But what does this mean for type hinting? It turns out you can tell Python to expect a string or None for the name parameter by joining these types with a pipe:

python
def greet(name: str | None = None) -> None:    if name is None:        print("Hi there!")    else:        print(f"Hi, {name}!")greet()# Expected result:# Hi there!

Type hints improve readability by making it clear that None is an expected value, not an accidental input. Also note, this syntax for type hinting (str | None) was introduced with Python 3.10 (2021), so for legacy systems, you may see Optional imported from the typing library and applied as Optional[str] instead.

Guard Early, Don’t Nest

You’ll find None particularly useful as a default function parameter, but take care not to over-nest conditionals with many requirements. Highly nested logic is much harder to read. For example, say you’d like to discount luxury items to 90% original prices. Here’s a nested Python function to do that:

python
def apply_discount(price, category=None):    if price is not None:        if category == "luxury":            return price * 0.9        return price    return Noneprint(apply_discount(100, category="luxury"))# Expected result:# 90.0

While this function fulfills its purpose, it’s tough to quickly understand which items actually get the discount.

Instead of nesting, rewrite the function using guard clauses to handle special cases early:

python
def apply_discount(price, category=None):    if price is None:        return None    if category == "luxury":        return price * 0.9    return priceprint(apply_discount(100, category="luxury"))# Expected result:# 90.0

Guard clauses keep None handling at the top of the function so the remaining logic only deals with meaningful, valid values–improving readability and reducing bugs.

Common Bugs and How to Avoid Them

Despite your efforts to follow best practices for null in Python, bugs are bound to show up sooner or later. Keep reading for some of the most common ones and how you can dodge them.

Forgetting a return Statement

As you saw before, Python functions always return something and default to None if no return value is specified. Your function might accidentally give back None if you forget to include a return statement:

python
def multiply(a, b):    result = a * b product = multiply(2, 3)print(product)# Expected result:# None

In this case, the function performs a calculation but does not return the result, so Python implicitly returns None.

This is one of the most common beginner mistakes, and it can cause issues later if the function result feeds into further calculations. Avoid this gotcha by ensuring functions that are meant to return a value explicitly include a return statement, and always test function outputs before using them in downstream logic.

Chained Method Calls on None (AttributeError)

Python objects often support method chaining, where the result of one method call is immediately used by the next:

python
name = " Sarah  "print(name.strip().upper())# Expected result:# SARAH

The problem is that unlike strings, lists, or user-defined objects, None doesn’t have any methods or attributes. If you attempt to chain methods on it, you’ll get an error. This function looks for a user by ID. Since no user exists with ID 3, the dictionary lookup returns None. Python then raises an AttributeError when you try to call .upper() on that None value:

python
def find_user(user_id):    users = {        1: "Sarah",        2: "Mike"    }    return users.get(user_id)print(find_user(3).upper())# Expected result:# AttributeError: 'NoneType' object has no attribute 'upper'

If a value is None in Python, any chained method calls on it fail immediately with an AttributeError. Always check for None before performing additional operations on a value.

Wrapping Up

If you’re looking for a null value in Python, None is it. This special singleton object represents the absence of a value and most commonly appears as a default return value or parameter for a function argument. Use is None or is not None to check for it, and remember that NaN, or not a number, serves a different purpose despite also being associated with missing data.

When working with None, add guard clauses early, use type hints where appropriate, and be careful not to accidentally return None by leaving out your return statement.

Lots to None tips to remember? You betcha. Take some time to interact with the AI Tutor to cement your newfound knowledge:

Join the Community

roadmap.sh is the 6th most starred project on GitHub and is visited by hundreds of thousands of developers every month.

Rank  out of 28M!

357K

GitHub Stars

Star us on GitHub
Help us reach #1

+90kevery month

+2.8M

Registered Users

Register yourself
Commit to your growth

+2kevery month

48K

Discord Members

Join on Discord
Join the community

RoadmapsGuidesFAQsYouTube

roadmap.shby@nilbuild

Community created roadmaps, best practices, projects, articles, resources and journeys to help you choose your path and grow in your career.

© roadmap.sh·Terms·Privacy·

ThewNewStack

The top DevOps resource for Kubernetes, cloud-native computing, and large-scale development and deployment.