35

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?

wim
  • 338,267
  • 99
  • 616
  • 750
  • 2
    *related:* [Python '==' vs 'is' comparing strings, 'is' fails sometimes, why?](http://stackoverflow.com/questions/1504717/python-vs-is-comparing-strings-is-fails-sometimes-why) – Felix Kling Jul 04 '11 at 10:46
  • possible duplicate of [When is the \`==\` operator not equivalent to the \`is\` operator? (Python)](http://stackoverflow.com/questions/3647692/when-is-the-operator-not-equivalent-to-the-is-operator-python) – user Mar 24 '14 at 13:54
  • related: http://stackoverflow.com/a/2577589/674039 – wim Mar 14 '15 at 08:49

5 Answers5

22

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
Petar Ivanov
  • 91,536
  • 11
  • 82
  • 95
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.

Vatine
  • 20,782
  • 4
  • 54
  • 70
  • 4
    Actually, there _is_ string interning. It just won't happen for dynamically created strings. – Katriel Jul 04 '11 at 11:03
  • 1
    @katrielalex there is a builtin `intern()` which lets you *explicitly* intern dynamically created strings; it just doesn't happen by itself. – Duncan Jul 04 '11 at 12:43
  • 1
    @katriealex: I think I actually meant "automatic and compulsory string-interning" (there are, I believe, some languages that do do that). – Vatine Jul 04 '11 at 13:41
  • @Duncan: I think the compiler automagically interns string literals that appear in the source, though. And @Vatine: ugh :p – Katriel Jul 04 '11 at 15:12
  • @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. – Duncan Jul 04 '11 at 17:30
  • @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 ==). – Vatine Jul 05 '11 at 15:40
  • @Duncan [`intern()`](https://docs.python.org/2.7/library/functions.html#intern) no longer exists on Python 3. – Boris Verkhovskiy Apr 16 '20 at 14:18
  • @Boris it does but it moved to `sys.intern()` – Duncan Apr 16 '20 at 15:55
  • So when is identity comparison required/preferred over value equality check? – wlnirvana Mar 28 '23 at 07:38
18

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.

sophros
  • 14,672
  • 11
  • 46
  • 75
Mikko Ohtamaa
  • 82,057
  • 50
  • 264
  • 435
  • 1
    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. – Dima Tisnek Feb 21 '12 at 10:58
  • 1
    what about types? `type("foo") is str` is probably ok – Jean-François Fabre Sep 21 '17 at 06:59
  • 2
    types are checked using `isinstance`, e.q. `isinstance("foo", str)`, or, if you want to exclude subclasses, `type("foo") == str` is enough. – Jindra Helcl Aug 02 '19 at 17:54
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
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.

talha06
  • 6,206
  • 21
  • 92
  • 147