Python:!= 和 "is not" 之间的区别

17

我不清楚语法!=is not之间的区别。它们似乎做相同的事情:

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

但是,当我在列表推导式中使用 is not 时,它会产生与使用 != 不同的结果。

>>> 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']
为什么在第一个列表中包含了 o ,但在第二个列表中没有?

3
当您查看这两个运算符的 Python 语言参考文档时,您看到了什么?这似乎很清楚:http://docs.python.org/reference/expressions.html#notin。有哪个部分让您困惑了吗? - S.Lott
@FChannel72,我认为表达式“c is not 'o'”中的“is”会引发“id(c) is not 'o'”的计算。由于数字(地址id(c))不是字符串,因此测试结果为True,因此c保留在内置列表中。 - eyquem
@FChannel72 问题在于我验证了你的结果,对于这两个表达式我得到了 ['h', 'e', 'l', 'l']。我想知道为什么如果存在 is,它会导致比较 id(c),那么为什么它不会导致将其与 id('o') 进行比较呢?实际上,似乎 c is not 'o' 被评估为 id(c)!=id('o')... 在我的 Python 2.7 中。 - eyquem
@FChannel72,我想Wooble在底部提供的链接让我觉得结果取决于Python的版本。你用的是哪个版本?我测试了“a = 257457895426”;“b = 257457895426”;“print a is b”,在Python 2.7中我得到了True。 - eyquem
1
这真的很奇怪,我无法重现这个问题:Python 2.7.5(默认值,Aug 25 2013, 00:04:04)[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin。输入“help”、“copyright”、“credits”或“license”获取更多信息。
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
5个回答

40

is用于测试对象标识(identity),而==用于测试对象的值相等性:

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

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

In [4]: a == b
Out[4]: True

2
原因是在op的示例中字符串无法工作,这是Python分配字符串给变量的方法的产物。由于字符串是不可变的,在全局命名空间中,包含相同字符串的两个变量将引用同一对象。 - Wilduck
1
你使用哪种Python?在Python 2.7中,我得到了“a is b”指令的True! - eyquem
这是使用Python 2.6.4。实现可以选择缓存某些对象。在我的系统上,“a”通过“is”测试,但“apple sauce”没有。 - tkerwin
对于好奇的人来说,这是因为 'a' 看起来像一个标识符(因此解释器会缓存它),但 'apple sauce' 不是(由于空格),所以如果你想要它被缓存,你必须通过 intern() 显式地进行缓存。 - ncoghlan

10

is not用于比较引用。 ==用于比较值。


在将a设置为123之后,为什么a==123会返回true? - ajwood
2
@ajwood:因为它们具有相同的值。==比较的是值。 - Wilduck
1
一个更好的问题是为什么在大多数实现中,“a is 123”返回True。(请参见https://dev59.com/DHVC5IYBdhLWcg3wZwTj) - Wooble
@Wooble 那确实是我本来想问的问题。 - ajwood

1
我想补充一点,它们绝对不是做相同的事情。我会使用!=。例如,如果您有一个 Unicode 字符串...
a = u'hello'
'hello' is not a
True
'hello' != a
False

使用 != 运算符时,Python 会将 str() 隐式转换为 unicode() 并进行比较;而使用 is not 运算符,则只有在完全相同的实例时才匹配。

1

根据你的困惑程度,这可能会有所帮助。

以下语句是相同的:

[c for c in s if c != 'o']
[c for c in s if not c == 'o']

0

我只是引用参考资料, is测试操作数是否相同,可能指的是同一个对象。而!=测试值。

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

这是一个无限循环,因为对象s永远不会等于由[]引用的对象,它引用了完全不同的对象。而将条件替换为s != []将使循环变为有限循环,因为在这里我们比较的是值,当所有值都被pop出s时,剩下的是一个空列表。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接