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.
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?
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.
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 .
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.
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.
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:
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