Search code examples
pythonpython-3.xcomparisonnonetypepep8

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?


Solution

  • 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.