views:

239

answers:

3

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.

I did some searching, and found this question, the top answer to which seemed to be just what I needed. Except the answer it gave was counter to my experience. Specifically, the answerer wrote:

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

I double-checked the type of the variable, and it was in fact of type str (not unicode or something). Is his answer just wrong, or is there something else afoot?

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.

+4  A: 

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.

pycruft
Whoops, apparently I forgot how implication works. Thanks. Also, how weird that someone asked such a similar question just as I was writing mine.
Coquelicot
`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
+3  A: 

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 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.

dan04
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
@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
On Nan: `x = float('NaN'); x is x` gives me `True`. How is this a counterexample?
Mike Boers
@Mike: `x is x` is always True. But that does not imply `x == x`. NaN is defined as not equal to itself.
dan04
@dan04 If bool_a's value is 3, then it's not a boolean type...
Coquelicot
@Coquelicot: In Python, every object has an implicit conversion to `bool`.
dan04
@dan04 that doesn't change the fact that type(3) is not 'bool'.
Coquelicot
@Coquelicot: in any case, `bool(a) != bool(b)` is equivalent to `a ⊕ b`.
ΤΖΩΤΖΙΟΥ
+1  A: 

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 for 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 a english point of view, equals is different from is)

pygabriel