Pitfalls of Python’s ‘is’ operator
I saw this post on Friendfeed, and thought I’d reproduce the code here, because it’s a really interesting Python snippet, and to me, basically says never, ever use the ‘is’ operator. Here’s the snippet that I just reproduced on Python 2.5.2 and 2.6.5:
In [1]: a = 500 In [2]: b = 500 In [3]: a == b Out[3]: True In [4]: a is b Out[4]: False In [5]: p = 50 In [6]: q = 50 In [7]: p is q Out[7]: True
Totally crazy, right?
The ‘is’ operator is testing “are these objects completely identical” In other words, are they pointing at the same implementation. For basic types like integer, things get complicated, because Python treats integer values between -5 and 256 differently. There’s some hint at this when looking at the documentation for the function PyInt_FromLong(), which takes a C++ long and returns the Python integer representation of that object. The comment there says:
The current implementation keeps an array of integer objects for all integers between -5 and 256, when you create an int in that range you actually just get back a reference to the existing object.
And thus, values outside of that range have different implementations, and thus, return False when comparing via ‘is’. There’s also some discussion of this on StackOverflow.
this is crazy. thanks for the post!
No, you shouldn’t use “is” to compare equality between two integers. That’s not quite the same as saying “don’t use it at all.”
“is” is not “==”. It compares the identity of two objects. It’s invaluable in specific constructs (“is not None” / “is not False”).
Is there a case where there’s a difference betwen “x == None” and “x is None” and/or “x == True” versus “x is True”? If the “is” operator isn’t safe for integer values, then I’m not sure why it would be safe for Boolean values.
It would seem to me that the only useful case for “is” (as you mentioned) is when comparing for identical object instances. For example, if you had some processing that may or may not modify a value, and you want to say something like “x is y” where y is the possibly modified object, then I can see that this is totally different than “x == y”. But for None/True/False? Can you explain in more detail?
You typically use `is` operator when comparing against Singletons like None, True, or False. Reasons being, the == operator can be overriden, but the `is` operator cannot; therefore you use `is` operator when you need to be sure that what you get is actually the Singleton you want to compare with. For example, a crazy object might define it’s __eq__ as always returning True, if you pass this object to a Python function that uses the idiom:
def foo(arg = None):
if arg == None: arg = []
#…
then a new list will be created instead of using the passed object. However:
def foo(arg = None):
if arg is None: arg = []
#…
will only create a new list if and only if arg is not passed or is passed the real None object, not an object that always compare equal to everything.
Another useful use of `is` is when comparing against a “sentinel” value. A common idiom:
sentinel = object()
lst = [a, b, c, sentinel, d, e, f]
lst_a, lst_b = split_at(sentinel, lst)
inside split_at, the sentinel object should be compared with `is` instead of ==.