When to use == and when to use is?
Asked Answered
M

6

36

Curiously:

>>> a = 123
>>> b = 123
>>> a is b
True
>>> a = 123.
>>> b = 123.
>>> a is b
False

Seems a is b being more or less defined as id(a) == id(b). It is easy to make bugs this way:

basename, ext = os.path.splitext(fname)
if ext is '.mp3':
    # do something
else:
    # do something else

Some fnames unexpectedly ended up in the else block. The fix is simple, we should use ext == '.mp3' instead, but nonetheless if ext is '.mp3' on the surface seems like a nice pythonic way to write this and it's more readable than the "correct" way.

Since strings are immutable, what are the technical details of why it's wrong? When is an identity check better, and when is an equality check better?

Melamine answered 4/7, 2011 at 10:41 Comment(3)
T
21

As far as I can tell, is checks for object identity equivalence. As there's no compulsory "string interning", two strings that just happen to have the same characters in sequence are, typically, not the same string object.

When you extract a substring from a string (or, really, any subsequence from a sequence), you will end up with two different objects, containing the same value(s).

So, use is when and only when you are comparing object identities. Use == when comparing values.

Tambourin answered 4/7, 2011 at 10:50 Comment(9)
Actually, there is string interning. It just won't happen for dynamically created strings.Ial
@katrielalex there is a builtin intern() which lets you explicitly intern dynamically created strings; it just doesn't happen by itself.Concent
@katriealex: I think I actually meant "automatic and compulsory string-interning" (there are, I believe, some languages that do do that).Tambourin
@Duncan: I think the compiler automagically interns string literals that appear in the source, though. And @Vatine: ugh :pIal
@katrielalex The compiler automatically interns strings in the source if the content of the string could be a valid Python identifier. Other strings are not interned, but duplicate strings in a single compilation unit will still be shared (but not shared with other compilation units). All of which is of course an implementation detail and subject to change at any time.Concent
@duncan, @katriealex It is still pretty unlikely that the result from os.path.splitext would ever be is-identical to a static string, though (even if it compares equal using ==).Tambourin
@Concent intern() no longer exists on Python 3.Sergo
@Boris it does but it moved to sys.intern()Concent
So when is identity comparison required/preferred over value equality check?Denominate
G
23

They are fundamentally different.

  1. == compares by calling the __eq__ method
  2. is returns true if and only if the two references are to the same object

So in comparision with say Java:

  1. is is the same as == for objects
  2. == is the same as equals for objects
Garey answered 4/7, 2011 at 10:51 Comment(0)
T
21

As far as I can tell, is checks for object identity equivalence. As there's no compulsory "string interning", two strings that just happen to have the same characters in sequence are, typically, not the same string object.

When you extract a substring from a string (or, really, any subsequence from a sequence), you will end up with two different objects, containing the same value(s).

So, use is when and only when you are comparing object identities. Use == when comparing values.

Tambourin answered 4/7, 2011 at 10:50 Comment(9)
Actually, there is string interning. It just won't happen for dynamically created strings.Ial
@katrielalex there is a builtin intern() which lets you explicitly intern dynamically created strings; it just doesn't happen by itself.Concent
@katriealex: I think I actually meant "automatic and compulsory string-interning" (there are, I believe, some languages that do do that).Tambourin
@Duncan: I think the compiler automagically interns string literals that appear in the source, though. And @Vatine: ugh :pIal
@katrielalex The compiler automatically interns strings in the source if the content of the string could be a valid Python identifier. Other strings are not interned, but duplicate strings in a single compilation unit will still be shared (but not shared with other compilation units). All of which is of course an implementation detail and subject to change at any time.Concent
@duncan, @katriealex It is still pretty unlikely that the result from os.path.splitext would ever be is-identical to a static string, though (even if it compares equal using ==).Tambourin
@Concent intern() no longer exists on Python 3.Sergo
@Boris it does but it moved to sys.intern()Concent
So when is identity comparison required/preferred over value equality check?Denominate
C
19

Simple rule for determining if to use is or == in Python

Here is an easy rule (unless you want to go to theory in Python interpreter or building frameworks doing funny things with Python objects):

Use is only for None comparison.

if foo is None

Otherwise use ==.

if x == 3

Then you are on the safe side. The rationale for this is already explained int the above comments. Don't use is if you are not 100% sure why to do it.

Countryman answered 4/7, 2011 at 19:47 Comment(3)
They Python way is readable code, meaning use == as long as that's what you mean (almost always). is None if x: if not x: is Python convention to check for None True False respectively. Real use of is comes when you examine complex data structures, e.g. assert not [l for l in mylist if l is mylist] a simple check against cycles in (plain) data structure.Outshout
what about types? type("foo") is str is probably okMenstruation
types are checked using isinstance, e.q. isinstance("foo", str), or, if you want to exclude subclasses, type("foo") == str is enough.Mckenney
X
0

It would be also useful to define a class like this to be used as the default value for constants used in your API. In this case, it would be more correct to use is than the == operator.

class Sentinel(object):
    """A constant object that does not change even when copied."""
    def __deepcopy__(self, memo):
        # Always return the same object because this is essentially a constant.
        return self

    def __copy__(self):
        # called via copy.copy(x)
        return self
Xenophobe answered 9/6, 2017 at 21:36 Comment(0)
R
0

You should be warned by PyCharm when you use is with a literal with a warning such as SyntaxWarning: "is" with a literal. Did you mean "=="?. So, when comparing with a literal, always use ==. Otherwise, you may prefer using is in order to compare objects through their references.

Rectangular answered 15/10, 2019 at 8:43 Comment(0)
P
0

I think this answer is missing a clear example of when to actually us is when comparing objects that are not None.

Several objects, e.g. lists, when assinged to other variables retain the object reference instead of creating a copy of the object. This may lead to undesired behavior if not properly understood:

>>> a = [1,2,3]
>>> b = a
>>> a[0] = 0
>>> b
[0,2,3]
>>> b is a
True
>>> b == a
True

However, if you create multiple instances of the same object they have the same definition but are essentially different objects:

>>> a = [1,2,3]
>>> b = [1,2,3]
>>> a[0] = 0
>>> b
[1,2,3]
>>> b is a
False
>>> b == a
True

When is comes to None, it is a special case. None is a singleton object, thus, instantiantion of None is restricted to one object. Therefore testing if an object is None with the is operator always works.

>>> a = None
>>> b = a
>>> b_ = None
>>> a is None
True
>>> b is a
True
>>> b_ is a
True
>>> b_ == a
True
>>> b == None
True

In conclusion, use is whenever you want to find out that both variables point to the exact same object, that is, if you change the state of a, b will be changed as well.

Pipistrelle answered 15/3 at 14:13 Comment(1)
“Several objects, e.g. lists, when assinged to other variables retain the object reference instead of creating a copy of the object.” — This is incorrect: all objects retain their object reference when assigned to another variable.Eupatrid

© 2022 - 2024 — McMap. All rights reserved.