Python 中 "is" 与 "==" 比较运算符的应用场景与区别

40 阅读2分钟

在 Python 编程中,"is" 和 "==" 是两个常用的比较运算符。有人在使用 Python 2.6.6 版本时,发现了一些奇怪的结果,他无法理解为什么下面的代码会出现这种情况:

a = "xx"
b = "xx"
a.__hash__() == b.__hash__()
True
a is b
True

a = "x" * 2
b = "x" * 2
a.__hash__() == b.__hash__()
True
a is b
True

n = 2
a = "x" * n
b = "x" * n
a.__hash__() == b.__hash__()
True
a is b
False

2、解决方案:

为了理解这个奇怪的结果,我们需要了解以下几点:

  • "is" 运算符用于比较两个变量是否指向同一个对象,而 "==" 运算符用于比较两个对象的是否相等。
  • 字符串常量是直接写在代码中的字符串,而不是通过编程计算得到的字符串。字符串常量总是被 "intern" 的,这意味着它们被存储在一个表中,以便重用。
  • 当使用 "a = "x"" 时,Python 编译器实际上会创建一个字符串常量 "x",然后将一个名称 a 分配给它。由于字符串常量是 "intern" 的,所以 a 和 b 使用的是同一个 "interned" 字符串 "x",因此 a is b 的结果为 True。
  • 当使用 "a = "x" * 2" 时,Python 编译器会在编译时计算字符串。它会生成代码,就好像你写了 a = "xx" 一样。因此,生成的字符串 "xx" 是 "interned" 的,这就是为什么 a is b 的结果为 True。
  • 当使用 "a = "x" * n" 时,Python 编译器不知道 n 在编译时的值。因此,它被迫在运行时实际输出字符串 "x",然后执行字符串乘法。由于这是在运行时完成的,虽然 "x" 是 "interned" 的,但生成的字符串 "xx" 不是。结果,这些字符串是 "xx" 的不同实例,因此 a is b 的结果为 False。

为了更好地理解这些概念,可以查看下面的代码:

def a1():
    a = "x"

def a2():
    a = "x" * 2

def a3():
    n = 2
    a = "x" * n

import dis
print("a1:")
dis.dis(a1)

print("a2:")
dis.dis(a2)

print("a3:")
dis.dis(a3)

在 CPython 2.6.4 中,这段代码输出的内容如下:

a1:
  4           0 LOAD_CONST               1 ('x')
              3 STORE_FAST               0 (a)
              6 LOAD_CONST               0 (None)
              9 RETURN_VALUE
a2:
  6           0 LOAD_CONST               3 ('xx')
              3 STORE_FAST               0 (a)
              6 LOAD_CONST               0 (None)
              9 RETURN_VALUE
a3:
  8           0 LOAD_CONST               1 (2)
              3 STORE_FAST               0 (n)

  9           6 LOAD_CONST               2 ('x')
              9 LOAD_FAST                0 (n)
             12 BINARY_MULTIPLY
             13 STORE_FAST               1 (a)
             16 LOAD_CONST               0 (None)
             19 RETURN_VALUE

从上面的输出中,我们可以看到在 a1 和 a2 中,Python 编译器在编译时计算了字符串常量,而在 a3 中,Python 编译器在运行时计算了字符串常量。

最后,需要注意的是,如果想要检查字符串相等,应该使用 a == b,而不是 a is b,因为 a is b 只会检查两个变量是否指向同一个对象,而 a == b 会检查两个对象的值是否相等。