Aleka
Aleka

Reputation: 288

Python None comparison with is keyword

So the is keyword returns true only if the two arguments point to the same object. My question is related to the snippet below.

This snippet

number = None
if number is None:
    print("PEP 8 Style Guide prefers this pattern")

Outputs

>>PEP 8 Style Guide prefers this pattern

Does this mean when I assign number = None then it is only by reference, because is checks if it is the same object. I'm so confused why this happens?? Am I wrong?? Why was this design choice made?

Upvotes: 1

Views: 106

Answers (2)

Kevin Languasco
Kevin Languasco

Reputation: 2426

This is because of two reasons.

1. Assignments in Python are by reference.

In the following code

x = object()
y = x
print(x is y)  # True
print(id(x))  # 139957673835552
print(id(y))  # 139957673835552

Calling object() creates a new structure in memory, whose unique identifier can be accessed with the id() function. You can imagine x and y being arrows pointing to the same object, and this is why their underlying identifier is the same in both cases.

As such, when assigning None to a variable, you're just saying "number is an alias, an arrow pointing to the object returned by writing None". You can check that

number = None
print(id(None), id(number))

will give you the same identifier two times. But wait! What if you do it for a big number like 100000?

number = 100000
print(id(100000), id(number))  # Different values!

This means that the same literal, written two times, can return different objects, bringing up the next reason.

2. The language guarantee for None

Note that no matter how many times you get the None identifier, you get the same one.

print(id(None))  # 139957682420224
print(id(None))  # 139957682420224
print(id(None))  # 139957682420224

This is because writing None doesn't create a new object, as in the first example, because the language specification guarantees that there's only one possible object of NoneType in memory. In other words, there's only one possible object returned by writing None, making comparisons with is work as expected. This is a good design choice: There's only one canonical way for saying that a variable (an arrow) points to nothingness.

In fact, using is is encouraged as the Pythonic way of checking that a variable is None.

You can also get the class of the object by writing

NoneType = type(None)

and notice how

NoneType() is None

is true.

Note: The uniqueness property is also satisfied by other literals, particularly small numbers, for performance reasons.

Upvotes: 3

chepner
chepner

Reputation: 532268

All assignments are by reference (see Facts and myths about Python names and values). However, the language guarantees that None is the only object of its type. That value is created at startup, and the literal None will always produce a reference to that value.

>>> a = None;  b = None
>>> a is b
True
>>> a = None
>>> b = None
>>> a is b
True

Compare to a literal like 12345, which may or may not produce a reference to an existing value of type int.

>>> a = 12345; b = 12345
>>> a is b
True
>>> a = 12345
>>> b = 12345
>>> a is b
False

Why this produces different results isn't really important, other than to say that an implementation can create new objects from int literals if it prefers.

Upvotes: 2

Related Questions