Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In python, why 'is' is preferred over '==' for checking if object in None [duplicate]

If I write this:

if x == None:
    x = 1

My pyCharm editor keeps suggesting that I should use 'is' instead of '==':

if x is None:
    x = 1

For any other equality check pyCharm does not suggest the use of 'is', like:

if x == 2:
    x = 1

Why is the 'is' operator preferred over the '==' operator while checking if object is None?

Why is it preferred only for None?

like image 588
Salil Agarwal Avatar asked Feb 09 '23 15:02

Salil Agarwal


1 Answers

Because None is a singleton, there is only ever one copy of the object in a Python program.

is is faster when testing against a single object, because only the pointers need to be equal. == tests for more information, the state of the objects tested needs to be the same too in that case.

This becomes more pronounced still if your x object implements a custom object.__eq__() method; it'll be called each time you use x == None, while x is None doesn't have such a hook. That means the interpreter has to execute some more Python code each time you do an equality test. Did I mention already that a simple pointer equality test (used for is) is fast?

That hook also makes it possible for a custom type to declare itself equal to None:

class Devious(object):
    def __eq__(self, other):
        return other is None

Now your x == None test will be true even though x is not actually None, but an instance of Devious instead. If you really wanted to know if x was set to None, only x is None will be able to detect that case.

None is not the only object you can test for identity with. Any time you need to know if a given name is referencing a specific object rather than a value, you should use is.

For example, sometimes you need to allow for None to be a valid value, but you want to detect if no value has been specified. Normally you could use None as a sentinel to detect if an argument has been left out:

def foo(arg1, optional=None):
    if optional is None:
        # no value given for optional

but if you want None to be a valid value, you'd use a different sentinel:

_sentinel = object()

def foo(arg1, optional=_sentinel):
    if optional is _sentinel:
        # no value given for optional

Now you can use foo(1, None) and it'll be correctly treated as a value.

like image 108
Martijn Pieters Avatar answered Feb 12 '23 04:02

Martijn Pieters