613

I noticed a Python script I was writing was acting squirrelly, and traced it to an infinite loop, where the loop condition was while line is not ''. Running through it in the debugger, it turned out that line was in fact ''. When I changed it to !='' rather than is not '', it worked fine.

Also, is it generally considered better to just use '==' by default, even when comparing int or Boolean values? I've always liked to use 'is' because I find it more aesthetically pleasing and pythonic (which is how I fell into this trap...), but I wonder if it's intended to just be reserved for when you care about finding two objects with the same id.

Coquelicot
  • 8,775
  • 6
  • 33
  • 37
  • 3
    How is this "counter to your experience"? NaN is the only built-in counterexample; you're simply misunderstanding directional relations. The spec says "For all built-in Python objects (like strings, lists, dicts, functions, etc.), if x is y, then x==y is also True.", not "For all built-in Python objects (like strings, lists, dicts, functions, etc.), if x==y, then x is y is also True." For some reason, you're pretending it says the latter. It doesn't. You see that equality matches, but is doesn't. That is perfectly allowed by the former quoted statement. – codetaku Jul 16 '14 at 15:20
  • Yup. My reading of that was completely confused. I edited it out of the question, because I don't think it will be useful to future readers. – Coquelicot Aug 21 '14 at 18:13
  • 2
    o1 is o2 => compares if o1 and o2 both points to same physical location in memory (in other words if they are same object). While, o1 == o2 => here python call the o1's __cmp__(o2) method, which ideally should compares the value and return True or False. (In other words it compares value) For JAVA people: In Java, to determine whether two string variables reference the same physical memory location by using str1 == str2. (called object identity, and it is written in Python as str1 is str2). To compare string values in Java, usestr1.equals(str2); in Python, use str1 == str2. – Jadav Bheda Oct 26 '16 at 05:50

4 Answers4

667

For all built-in Python objects (like strings, lists, dicts, functions, etc.), if x is y, then x==y is also True.

Not always. NaN is a counterexample. But usually, identity (is) implies equality (==). The converse is not true: Two distinct objects can have the same value.

Also, is it generally considered better to just use '==' by default, even when comparing int or Boolean values?

You use == when comparing values and is when comparing identities.

When comparing ints (or immutable types in general), you pretty much always want the former. There's an optimization that allows small integers to be compared with is, but don't rely on it.

For boolean values, you shouldn't be doing comparisons at all. Instead of:

if x == True:
    # do something

write:

if x:
    # do something

For comparing against None, is None is preferred over == None.

I've always liked to use 'is' because I find it more aesthetically pleasing and pythonic (which is how I fell into this trap...), but I wonder if it's intended to just be reserved for when you care about finding two objects with the same id.

Yes, that's exactly what it's for.

Ernest Friedman-Hill
  • 80,601
  • 10
  • 150
  • 186
dan04
  • 87,747
  • 23
  • 163
  • 198
  • Thanks, very clear answer. I'm not sure I agree about comparing booleans though (unless you just meant you shouldn't compare to a boolean literal). If I have two boolean variables or expressions, I would think it would be valid to do bool_a != bool_b as a shorthand for xor. – Coquelicot Jun 07 '10 at 09:14
  • 4
    @Coquelicot: That wouldn't work because Python allows anything to be used as a boolean expression. If you have bool_a == 3 and bool_b == 4, then bool_a != bool_b, but bool_a xor bool_b is false (because both terms are true). – dan04 Jun 07 '10 at 12:57
  • On Nan: `x = float('NaN'); x is x` gives me `True`. How is this a counterexample? – Mike Boers Jun 07 '10 at 13:00
  • 4
    @Mike: `x is x` is always True. But that does not imply `x == x`. NaN is defined as not equal to itself. – dan04 Jun 07 '10 at 13:12
  • @dan04 If bool_a's value is 3, then it's not a boolean type... – Coquelicot Jun 07 '10 at 22:46
  • @Coquelicot: In Python, every object has an implicit conversion to `bool`. – dan04 Jun 09 '10 at 05:11
  • @dan04 that doesn't change the fact that type(3) is not 'bool'. – Coquelicot Jun 11 '10 at 22:21
  • 1
    @Coquelicot: in any case, `bool(a) != bool(b)` is equivalent to `a ⊕ b`. – tzot Jul 01 '10 at 08:21
  • 3
    Regarding speed, I though that for checking if a string was modified (e.g. result returned from re.sub) comparing large strings for `is` equality instead of `==` would be faster. This was barely the case an timeit showed a mere **0.4%** speed improvement. In my case it's not worth the risk that re.sub starts changing the strings in the future. – estani Oct 30 '12 at 10:56
  • 5
    For anyone looking at this years later, this still holds true for Python 3. – RyPeck Nov 15 '13 at 22:07
  • @estani, your recommendation helps avoid one of the most insidious gotchas in Python, comparison of `None`s converted to strings: `str(None) is 'None'` evaluates to `False` but `str(None) == 'None'` evaluates to True. This is often required in evaluating database query results. Object identity of None is preserved despite conversion to str (an immutable type) and despite the fact that both `str` objects look the same (and `repr` the same) in the console. I can't imagine any application where you'd want to use `is` instead of `==` to compare strings. – hobs Mar 24 '14 at 16:36
  • what should I use for comparing strings? – Incerteza Oct 10 '14 at 09:42
  • @アレックス, use `==` to compare strings for equality. Almost always use `==`. – Jasmijn Jan 10 '16 at 20:50
  • I can't find any code that shows NaN is a counterexample. float('nan') is float('nan') False – beauxq Feb 15 '16 at 23:04
  • 2
    @beauxq: Try `nan = float('nan'); nan is nan; nan == nan` – dan04 Feb 15 '16 at 23:29
  • Who decided to give me an unexplained downvote on a 5.7-year-old answer? – dan04 Feb 17 '16 at 19:51
  • This just got me: `"foo" == u"foo"` but `"foo" is not u"foo"` – grantpatterson Aug 30 '16 at 23:15
  • does this work on characters as well? I had an issue before where I could check a character with `is` but I can't check if a string's value is equal to another with `is` because they are technically two different objects in my code. – Kyle Calica-St Jun 26 '19 at 06:25
  • @dan04 Where dd you quote this from - "pythonic (which is how I fell into this trap..."? – technazi Apr 14 '20 at 15:39
  • 2
    @technazi: It's from the OP. – dan04 Apr 14 '20 at 15:55
  • Using `is` for comparing values, one get: `SyntaxWarning: "is" with a literal. Did you mean "=="?` – Timo Apr 24 '21 at 12:11
  • 2
    `Not always. NaN is a counterexample.` +1 for pedantry. – CoffeeTableEspresso Jun 07 '22 at 17:21
  • -1 because I found this question when looking for string matching, but it doesn't actually talk about that. (the blame is also with the question, I guess) – Kotlopou May 01 '23 at 15:28
280

I would like to show a little example on how is and == are involved in immutable types. Try that:

a = 19998989890
b = 19998989889 +1
>>> a is b
False
>>> a == b
True

is compares two objects in memory, == compares their values. For example, you can see that small integers are cached by Python:

c = 1
b = 1
>>> b is c
True

You should use == when comparing values and is when comparing identities. (Also, from an English point of view, "equals" is different from "is".)

Falko
  • 17,076
  • 13
  • 60
  • 105
pygabriel
  • 9,840
  • 4
  • 41
  • 54
  • 6
    Another simple example, `datetime.date.today() == datetime.date.today()` ==> True but `datetime.date.today is datetime.date.today()` ==> False because they are equivalent date objects, but they're still different objects. – B Robster Jun 17 '13 at 21:54
  • 5
    Another dangerous example that your recommendation avoids: `str(None) is 'None'` evaluates to `False` but `str(None) == 'None'` evaluates to `True` – hobs Mar 24 '14 at 16:46
  • 8
    Here's one with strings: ``x = 'foo'; y = 'bar'.replace('bar', 'foo'); (x is y) == False`` – ariddell Feb 02 '15 at 23:27
  • 4
    Another example that I like: 'a'*50 == 'a'*50 (returns True), whereas 'a'*50 is 'a'*50 (returns False) – Emre Sevinç Aug 14 '15 at 07:27
76

The logic is not flawed. The statement

if x is y then x==y is also True

should never be read to mean

if x==y then x is y

It is a logical error on the part of the reader to assume that the converse of a logic statement is true. See http://en.wikipedia.org/wiki/Converse_(logic)

xubio
  • 881
  • 6
  • 6
  • 1
    @BrentHronik It's more related to the memory addresses and the `id` of the object rather than the actual logic. –  Dec 17 '15 at 23:25
  • Is the first statement true if x and y are both NaN? Possibly even with the same object id? In other languages (C++) it is supposed to be the case that NaN is never equal to itself. – Heather Sep 04 '17 at 08:32
27

See This question

Your logic in reading

For all built-in Python objects (like strings, lists, dicts, functions, etc.), if x is y, then x==y is also True.

is slightly flawed.

If is applies then == will be True, but it does NOT apply in reverse. == may yield True while is yields False.

Community
  • 1
  • 1
pycruft
  • 66,157
  • 1
  • 20
  • 12
  • `is` implies `==` is only necessarily true for built-in types. One can easily write a class where an object does not equal itself. – Mike Boers Jun 07 '10 at 13:01
  • By saying "If `is` applies then `==` will be True, but it does NOT apply in reverse." you're just stating what the OP observed. –  Dec 17 '15 at 23:26