在 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 会检查两个对象的值是否相等。