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 greeting
?"
"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 numbers
and 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?
Coming up…
Understanding
None
When functions return
None
Using
None
as a default argument in functions, especially in place of mutable data typesSome other uses of
None
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
. 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:
This returns True
, which means there's only one instance of None
.
And None
is only equal to itself:
The output from this code shows that only the first one is True
:
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 None
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:
STEPHEN
None
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 None
.
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:
None
A function can also have a line with only the return
keyword and nothing after it. This function also returns None
.
You need to return the string to fix this problem:
Now, this outputs the string with the greeting, as expected:
Hello, Kate!
But functions with no return
statements aren't the only place where we see None
.
Using 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 greeting
is None
.
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.
Using 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:
['Ishaan', 'Sarah']
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:
True
When you call the function twice without a second argument, you don't create two separate teams. The names red_team
and 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:
False
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 if
statement:
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 bool(None)
returns False
.
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 None
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: None
.
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 1
with 0
points. However, you'll fill in the player's name later in the program, so you use None
as the value associated with "name"
.
And you can always check whether the name value is still blank using an if
statement:
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!
The method 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 False
.
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, False
, and 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 None
?
Code in this article uses Python 3.12
Stop Stack
#35
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
zoneinfo
anddatetime
modules • The first article in a two-part mini-seriesA Slicing Story Are you sure you know everything there is to know about Python's
slice
object?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
Subscribers: 1,160