17

I'm unclear about the difference between the syntax != and is not. They appear to do the same thing:

>>> s = 'a'
>>> s != 'a'
False
>>> s is not 'a'
False

But, when I use is not in a list comprehension, it produces a different result than if I use !=.

>>> s = "hello"
>>> [c for c in s if c is not 'o']
['h', 'e', 'l', 'l', 'o']
>>> [c for c in s if c != 'o']
['h', 'e', 'l', 'l']

Why did the o get included in the first list, but not the second list?

Channel72
  • 24,139
  • 32
  • 108
  • 180
  • 3
    When you looked at the Python language reference for these two operators, what did you see? This seems clear: http://docs.python.org/reference/expressions.html#notin. What part confused you? – S.Lott Apr 25 '11 at 19:40
  • @FChannel72 I think that the presence of **is** in the expression ``c is not 'o'`` provokes the evaluation of ``id(c) is not 'o'`` . Since a number (the address id(c)) isn't a string , the test gives True as a result, so **c** is kept in the built list. – eyquem Apr 25 '11 at 20:04
  • @FChannel72 The problem is that I verified your results and I obtain ``['h', 'e', 'l', 'l']`` for the two expressions ! I was wondering why, if the presence of ``is`` provokes to compare id(c), it wouldn't provoke to compare it to id('o') too. In fact, it seems that ``c is not 'o'`` is evaluated as ``id(c)!=id('o')`` ... in my Python 2.7 – eyquem Apr 25 '11 at 20:13
  • @FChannel72 The link given by Wooble at the bottom makes me think that the results depend on the version of Python . Which one have you ? I tested ``a = 257457895426`` ; ``b = 257457895426`` ; ``print a is b`` and I got True, in Python 2.7 – eyquem Apr 25 '11 at 20:37
  • 1
    This is really strange, I can't recreate this: Python 2.7.5 (default, Aug 25 2013, 00:04:04) [GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> s = "hello" >>> [c for c in s if c is not 'o'] ['h', 'e', 'l', 'l'] >>> [c for c in s if c != 'o'] ['h', 'e', 'l', 'l'] – michaelsnowden Jan 27 '14 at 03:37

5 Answers5

40

is tests for object identity, but == tests for object value equality:

In [1]: a = 3424
In [2]: b = 3424

In [3]: a is b
Out[3]: False

In [4]: a == b
Out[4]: True
tkerwin
  • 9,559
  • 1
  • 31
  • 47
  • 2
    The reason is not worked for the strings in the op's example is an artifact of python's method of assigning strings to variables. Since strings are immutable, in the global namespace, two variables which contain the same string will be referencing the same object. – Wilduck Apr 25 '11 at 19:41
  • 1
    What sort of Python do you use ? With Python 2.7, I obtain True for the instruction ``a is b`` ! – eyquem Apr 25 '11 at 20:00
  • This is using Python 2.6.4. The implementation can make the choice to cache certain objects. On my system, 'a' passes the `is` test, but 'apple sauce' does not. – tkerwin Apr 25 '11 at 20:54
  • For the curious, that happens because 'a' looks like an identifier (so the interpreter caches it), but 'apple sauce' does not (due to the space), so if you want it cached you must do so explicitly via `intern()`. – ncoghlan Apr 26 '11 at 03:24
10

is not compares references. == compares values

c1de0x
  • 101
  • 2
1

I'd like to add that they definitely do not do the same thing. I would use !=. For instance if you have a unicode string....

a = u'hello'
'hello' is not a
True
'hello' != a
False

With !=, Python basically performs an implicit conversion from str() to unicode() and compares them, whereas with is not, it matches if it is exactly the same instance.

std''OrgnlDave
  • 3,912
  • 1
  • 25
  • 34
1

Depending on how you were confused, this might help.

These statements are the same:

[c for c in s if c != 'o']
[c for c in s if not c == 'o']
Chris
  • 435
  • 5
  • 12
0

I am just quoting from reference, is tests whether operands are one and same, probably referring to the same object. where as != tests for the value.

s = [1,2,3]
while s is not []:
   s.pop(0);

this is a indefinite loop, because object s is never equal to an object reference by [], it refers to a completely different object. where as replacing the condition with s != [] will make the loop definite, because here we are comparing values, when all the values in s are pop'd out what remains is a empty list.

saikumarm
  • 1,565
  • 1
  • 15
  • 30