何时使用 == 和何时使用 is?

36

有趣的是:

>>> a = 123
>>> b = 123
>>> a is b
True
>>> a = 123.
>>> b = 123.
>>> a is b
False

看起来a is b被定义为id(a) == id(b)。这种方式很容易出现错误:

basename, ext = os.path.splitext(fname)
if ext is '.mp3':
    # do something
else:
    # do something else

一些 fnames 意外地出现在 else 块中。修复很简单,我们应该使用 ext == '.mp3'而不是 if ext is '.mp3',但表面上看来 if ext is '.mp3' 看起来像是一种不错的 Pythonic 写法,比“正确”的写法更可读。

由于字符串是不可变的,为什么它是错误的技术细节是什么?何时使用身份检查更好,何时使用相等性检查更好?


2
Python中'=='和'is'比较字符串,为什么有时候'is'会失败? - Felix Kling
相关:https://dev59.com/R3E85IYBdhLWcg3w2Hfs#2577589 - wim
5个回答

23

它们本质上不同。

  1. == 通过调用 __eq__ 方法进行比较
  2. is 仅在两个引用指向同一对象时返回 true

因此,与 Java 相比:

  1. is 对于对象来说与 == 相同
  2. == 对于对象来说相当于 equals

21
据我所知,is用于检查对象的身份等价性。由于没有强制进行“字符串缩略”,通常情况下只是恰好具有相同字符序列的两个字符串不是同一字符串对象。
当从字符串(或任何序列)中提取子字符串时,您将得到两个不同的包含相同值的对象。
因此,仅在比较对象标识时使用is。在比较值时使用==

4
实际上,确实有字符串驻留。只是对于动态创建的字符串不会发生这种情况。 - Katriel
1
@katrielalex,Python中有一个内置的intern()函数,可以让你显式地将动态创建的字符串放入字符串池中,但它不会自动发生。 - Duncan
1
@katriealex:我想我实际上是指“自动和强制的字符串内部化”(我相信有一些语言确实这样做)。 - Vatine
@Duncan:我认为编译器会自动对源代码中出现的字符串常量进行内部化处理。而且 @Vatine:唉 :p - Katriel
编译器会自动将字符串在源代码中进行内部化,如果字符串的内容可以成为有效的Python标识符。其他字符串不会被内部化,但是单个编译单元中的重复字符串仍然会被共享(但不与其他编译单元共享)。当然,所有这些都是实现细节,随时可能发生变化。 - Duncan
显示剩余4条评论

18

如何在Python中决定使用is还是==的简单规则

以下这个简单规则适用于大多数情况(除非你想要深入了解Python解释器或构建对Python对象进行有趣操作的框架):

只有在比较None时才使用 is。

if foo is None

否则使用 ==。

if x == 3

那么你就安全了。上面的评论已经解释了这样做的原因。如果你不确定为什么要这样做,不要使用它。


1
Python的编程风格强调可读性,因此只要你的意思是“相等”,就使用==(几乎总是如此)。 is Noneif x:if not x: 是Python惯用语,分别用于检查NoneTrueFalseis 的真正用途是在检查复杂数据结构时,比如说,检查纯数据结构中是否有循环引用,可以使用类似这样的断言:assert not [l for l in mylist if l is mylist] - Dima Tisnek
1
类型呢?type("foo") is str应该没问题。 - Jean-François Fabre
2
类型检查使用 isinstance,例如 isinstance("foo", str),如果想要排除子类,可以使用 type("foo") == str - Jindra Helcl

0

定义一个类,作为API中常量的默认值,也会非常有用。在这种情况下,使用is运算符比使用==运算符更加正确。

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
当您使用文字面值的is时,PyCharm应该会发出警告,例如SyntaxWarning: "is" with a literal. Did you mean "=="?。因此,在与文字面值进行比较时,请始终使用==。否则,您可能更喜欢使用is来通过它们的引用比较对象。

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