【问题标题】:When to use == and when to use is?什么时候用==,什么时候用is?
【发布时间】:2011-09-28 01:28:20
【问题描述】:

奇怪的是:

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

一些 fname 意外地出现在 else 块中。修复很简单,我们应该改用ext == '.mp3',但从表面上看if ext is '.mp3' 似乎是一种不错的pythonic 方式来编写它,并且它比“正确”方式更具可读性。

既然字符串是不可变的,那么它为什么会出错的技术细节是什么?什么时候身份检查更好,什么时候平等检查更好?

【问题讨论】:

标签: python memory equality


【解决方案1】:

它们本质上是不同的。

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

所以与说 Java 相比:

  1. 对于对象,is== 相同
  2. 对于对象,==equals 相同

【讨论】:

    【解决方案2】:

    据我所知,is 检查对象身份等价性。由于没有强制的“字符串暂留”,因此恰好在序列中具有相同字符的两个字符串通常不是同一个字符串对象。

    当您从字符串中提取子字符串(或者,实际上,从序列中提取任何子序列)时,您最终会得到两个不同的对象,包含相同的值。

    因此,当且仅当您比较对象身份时才使用is。比较值时使用==

    【讨论】:

    • 其实有字符串实习。动态创建的字符串不会发生这种情况。
    • @katrielalex 有一个内置的intern() 可以让你显式实习生动态创建字符串;它只是不会自行发生。
    • @katriealex:我想我的意思实际上是“自动和强制的字符串实习”(我相信有些语言可以做到这一点)。
    • @Duncan:不过,我认为编译器会自动实习生出现在源代码中的字符串文字。还有@Vatine:呃:p
    • @katrielalex 如果字符串的内容可能是有效的 Python 标识符,编译器会自动在源中实习字符串。其他字符串不会被interned,但单个编译单元中的重复字符串仍将被共享(但不与其他编译单元共享)。当然,所有这些都是实施细节,随时可能发生变化。
    【解决方案3】:

    在 Python 中确定是否使用 is 或 == 的简单规则

    这是一个简单的规则(除非你想在 Python 解释器中进行理论研究或构建框架,用 Python 对象做一些有趣的事情):

    仅用于None比较。

    if foo is None
    

    否则使用 ==。

    if x == 3
    

    那么你就安全了。上面的 cmets 已经解释了这样做的基本原理。如果您不能 100% 确定为什么要这样做,请不要使用 is。

    【讨论】:

    • 他们的 Python 方式是可读的代码,这意味着使用 ==,只要这就是你的意思(几乎总是)。 is None if x: if not x: 是分别检查None True False 的Python 约定。当您检查复杂的数据结构(例如assert not [l for l in mylist if l is mylist] 对(普通)数据结构中的循环进行简单检查。
    • 类型呢? type("foo") is str 应该没问题
    • 使用isinstance检查类型,例如isinstance("foo", str),或者,如果你想排除子类,type("foo") == str 就足够了。
    【解决方案4】:

    定义一个这样的类作为 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
    

    【讨论】:

      【解决方案5】:

      当您将is 与带有警告的文字(例如SyntaxWarning: "is" with a literal. Did you mean "=="?)一起使用时,PyCharm 应该会警告您。因此,在与文字进行比较时,请始终使用==。否则,您可能更喜欢使用 is 来通过引用比较对象。

      【讨论】:

        猜你喜欢
        • 2012-08-07
        • 2012-04-05
        • 1970-01-01
        • 2020-01-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多