Discover more from The Python Coding Stack • by Stephen Gruppetta
This Page Is Intentionally Left Blank • The Story of `None`
Understanding Python's `None`
You've seen exam papers or official booklets that have this page:
A blank page with the text "This page is intentionally left blank" in the middle. And, of course, the irony is that by having that text on the page, well, the page is no longer blank.
We face a similar "paradox" when we try to understand Python's
None or its equivalent in other languages. You can't have nothing. So, you have something that represents nothing. Just like the text on the page is text that's telling you that there's no text on the page.
Let's explore emptiness and nothingness in Python.
Not All Emptiness Is Equal
When teaching live courses, I often show the following line of code and ask my students: "What's stored in the variable
"Nothing" is a common reply. But this variable is not empty. It contains a string. The string is empty, but the variable isn't. The name
greeting refers to an object of type string and, therefore, has access to all the string methods. An empty string is something—it's not nothing.
How about other empty structures, such as the following empty list?
The same logic applies—
numbers is not empty. It contains a list that's empty. But
greeting have different properties and have access to different methods since they're different data types. They're both empty, but they're not equal.
Let's understand this idea better with a fictitious "data type"—the bus. Imagine an empty bus (the vehicle, not the bus inside your computer!) There are plenty of seats, and they're all empty. This is an empty bus. But it's not "nothing". It's a bus, and it has "bus properties"—it can drive and open its doors and so on. And you can have passengers board the bus and sit in the seats. The bus is no longer empty now.
But what if what you want is not an empty bus but nothing whatsoever?
When functions return
Noneas a default argument in functions, especially in place of mutable data types
Some other uses of
Something To Represent Nothing
So, if the examples you saw do not represent "nothing", what does?
Python has a data type just for this. The data type is
NoneType, which only has one instance,
None is one of Python's constant values. It's also a singleton, which means there's only one instance of
None. Here's confirmation of this:
True, which means there's only one instance of
None is only equal to itself:
The output from this code shows that only the first one is
True False False False
None is not the same as an empty string or list, and it's not the same as the number
0. The number
0 is a number, the empty string is a string, and the empty list is a list. But
None is none of those! It's nothing.
Except that it is an object. But it's an object that represents nothing. It's the text that says: "This page is intentionally left blank."
But why do we need something to represent nothing in a Python program? In the rest of this article, we'll explore a few examples of where we see or use
None in Python.
Functions That Return
Here's a common pitfall for those learning about different data type's methods:
Here's the output from the two
print() functions in this code:
When you call
name.upper(), the method returns a string that's the uppercase version of the original string. However,
numbers.append() behaves differently. It changes the original list and doesn't return anything—it returns nothing. But wait a second, we can't have nothing in a computer program. Instead, we have something that represents nothing, and that's
Every function or method returns something. If there's nothing returned explicitly in a function definition, it returns
None. Here's an example:
Note that the function definition doesn't have a
return statement. This doesn't mean it doesn't return anything. A function with no
return statement returns
None. You can see this when you run this code:
A function can also have a line with only the
return keyword and nothing after it. This function also returns
You need to return the string to fix this problem:
Now, this outputs the string with the greeting, as expected:
But functions with no
return statements aren't the only place where we see
None To Show When An Argument Hasn't Been Set
Let's get back to the function defined in the previous section, and let's add a default argument for one of the parameters:
The function can now be used either with one or two arguments. If the greeting is not provided, the function returns a different string:
Kate has arrived Hi, James!
Note that this function is not very exciting! I'm using a short and simple function to demonstrate the concepts, but the same applies to more interesting and complex functions.
You use the empty string as a default value for
greeting and then check whether
greeting is equal to the empty string in the function definition.
This is perfectly fine, but what if you want a function where the empty string is a valid input argument? You cannot do so with this function since if you pass the empty string, the function will return the alternative string.
So, another option is to use
None as the default value. This also has the advantage of making the intention more explicit. Recall that
None is an object that represents nothingness, so using
None makes it clear that this refers to the situation when no argument is passed. But remember that
None is itself an argument—we're back to having something to represent nothing!
When you omit the argument passed to
greeting, the function uses
None as a placeholder to represent the missing argument. The
if statement now checks whether
You could use
greeting == None in the
if statement, but it's more common to use the
is keyword in this situation since
None is a singleton, which means there's only one instance of
None. Indeed, PEP 8, the Python style guide, suggests that you should always use the identity operator
is in these scenarios.
None When You Need A Mutable Default Argument
In the example in the previous section, you can choose whether to use the empty string or
None as the default value. However, there are situations when you don't have a choice.
Have a look at this example, which is incorrect. You'll see why this fails soon:
As in the earlier section, this is a simple function, and you don't need to create a function to perform this action. However, I want to use a short example to demonstrate these concepts.
You can call this function with either one or two arguments. The idea behind this code is that if you don't provide an existing list for
team, then an empty list is used as the default value.
Let's start using this function with a list that already exists:
You start with a list that already contains Mary and Kate. Then, you add James using the function you just defined. The result is what you'd expect:
['Mary', 'Kate', 'James']
Now, try using the function without a second argument:
The second call to
add_player_to_team() only has the player's name. Therefore, the default value for
team is used, which is an empty list. Here's the output:
['Mary', 'Kate', 'James'] ['Ishaan']
The second line in the output shows a new list containing Ishaan's name. So, all appears to be working, right? Not so fast…
Let's try to create a third team, the green team, using the same function with only one argument. Note that I'm adding to the code in the previous code examples in this section:
Here's the output from this code:
['Mary', 'Kate', 'James'] ['Ishaan'] ['Ishaan', 'Sarah']
And here's the problem. The green team, which is the third one you create, contains two names. It contains Sarah, but it also contains Ishaan, the name you add to a different team, the red team, earlier in the code.
We can go further and look at the red team members again. I'm not showing the whole code, but this also carries on from the previous code examples in this section:
This outputs the following list:
So, Sarah was added to the red team as well as the green team. In fact, we can go further:
This outputs the following result:
When you call the function twice without a second argument, you don't create two separate teams. The names
green_team refer to the same object.
This is not the case when compared with the blue team, which is the first one you create:
The output shows that these are not the same object:
You create the blue team without relying on the function's default argument.
When you define the function with a list as a default value, an empty list is created and associated with this function. Lists are mutable data types, so you can modify their contents, such as by adding items.
Therefore, when you call the function without a second argument, the function uses the same default list each time. It doesn't create a new one each time you call the function.
How can we fix this? By never using mutable data types as default arguments in functions. Use
None instead. I'm showing the outputs from each
print() function as a comment directly in the code for clarity:
This works as you intended now. When you create the green team in the third function call, a brand new list is created.
The default argument is no longer an empty list. Instead, you create an empty list as part of the function's code. Therefore, a new list is created each time you call the function using the default argument.
You may be tempted to simplify the
You could use this instead of
if team is None since
None is falsy, which means it's treated as
False in statements that expect a data type which can be interpreted as a Boolean. This is the same as stating that
However, what if you want to pass an empty list as the second argument? An empty list is also falsy. Therefore, the code in the
if block will be executed. This may not make much difference in this example, but it can in other situations. So, it's best to be explicit and check whether
team is None to avoid ambiguity.
Some Other Uses of
You've already seen how you can assign
None to a variable name, for example:
You can use this when you want to create the variable name in your program but don't want to assign anything to it just yet. Since you can't leave it blank, you assign Python's object representing nothingness:
You can use the same principle in data structures when you want to have "empty" values. Here's an example:
You create a dictionary to hold key data about the player in a game. The player starts at level
0 points. However, you'll fill in the player's name later in the program, so you use
None as the value associated with
And you can always check whether the name value is still blank using an
Recall that we prefer to check for identity using
is when dealing with
None rather than checking for equality using
The same concept applies when you define a class and you need to create an attribute without assigning any data to it. Let's convert the example above into a short class:
You define the instance attribute
.name in the class's
__init__() method but you leave it "blank". And by now, you know that "leaving something empty" means assigning
None to it!
assign_name() then takes care of replacing
None with another value.
And I'll finish with something we discussed earlier in this article.
None is not the same as an empty data structure or the number
0. And it's not the same as the Boolean
All of these are falsy, which means that they can be considered as false in contexts where Python needs to determine if something is true or false. Here's confirmation that empty structures, zero,
None are all falsy:
All of these lines return
False. However, these objects are all different. They are different data types, including
None, which is the only instance of
NoneType. And whereas you can use
False instead of
0 in your code, you cannot use
None in the same way:
Enough Talking About Nothing
It's surprising how much there is to say about nothing! The concept of
None can be confusing. We need a Python object that represents nothingness. However, this object takes up some memory and can be assigned to variable names. So it is something!
This article started with a comparison with those pages in some books with the text "This page is intentionally left blank". There is text to show there is no text. Similarly,
None is an object to indicate there is no object!
Another analogy we can use is the term "vacuum", which represents the absence of any matter. We need the concept of a vacuum to talk about nothingness in physics!
Can you think of other analogies from the real world that can be used to represent Python's
Code in this article uses Python 3.12
Recently published articles on The Python Coding Stack:
The Function Room (Monty and The White Room Series #2) Part 2 in the Monty and The White Room Series • Understanding functions
Monty and The White Room (Monty and The White Room Series #1) Understanding a Python program through The White Room analogy • Part 1
5:30am • Timezone Headaches (Part 1) I need Python's help to figure out the time of my talk • Dealing with timezones and daylight saving with Python's
datetimemodules • The first article in a two-part mini-series
A Slicing Story Are you sure you know everything there is to know about Python's
Coding, Fast and Slow, Just Like Chess An essay: How adapting from fast to slow chess got me thinking about coding in Python
Recently published articles on Breaking the Rules, my other substack about narrative technical writing:
The Selfish Reason (Ep. 13) Another reason for authors to innovate • Enjoying the writing process
The Consequential Detail (Ep. 12). Can a single letter or one blank line make a difference? (Spoiler Alert: Yes)
The Unexpected Audience (Ep. 11). What I'm learning from listening to Feynman's physics lectures
The Story So Far (Mid-Season* Review). Are you back from your holidays? Catch up with what you've missed
Broken Rules (Ep. 10). Let's not lose sight of why it's good to break the rules—sometimes
Frame It • Part 2 (Ep. 9). Why and when to use story-framing
Stats on the Stack
Age: 6 months, 1 week, and 2 days old
Number of articles: 35