有人可以在python 2.6.6上解释我这个奇怪的结果吗?
>>> a = "xx"
>>> b = "xx"
>>> a.__hash__() == b.__hash__()
True
>>> a is b
True # ok.. was just to be sure
>>> a = "x" * 2
>>> b = "x" * 2
>>> a.__hash__() == b.__hash__()
True
>>> a is b
True # yeah.. looks ok so far !
>>> n = 2
>>> a = "x" * n
>>> b = "x" * n
>>> a.__hash__() == b.__hash__()
True # still okay..
>>> a is b
False # hey! What the F... ?
答案 0 :(得分:18)
is
运算符会告诉您两个变量是否指向内存中的同一对象。它很少有用,常常与==
运算符混淆,后者告诉您两个对象是否“看起来相同”。
当用于短字符串文字之类的东西时,它尤其令人困惑,因为Python编译器为了提高效率而实现这些。换句话说,当您编写"xx"
时,编译器(发出字节码)会在内存中创建一个字符串对象,并导致所有文字"xx"
指向它。这就解释了为什么你的前两个比较是真的。请注意,您可以通过调用id
来获取字符串的id,这些(至少在CPython上可能是)它们在内存中的地址:
>>> a = "xx"
>>> b = "xx"
>>> id(a)
38646080
>>> id(b)
38646080
>>> a is b
True
>>> a = "x"*10000
>>> b = "x"*10000
>>> id(a)
38938560
>>> id(b)
38993504
>>> a is b
False
第三个是因为编译器没有插入字符串a
和b
,无论出于何种原因(可能是因为它不够聪明,没有注意到变量n
是定义一次然后从未修改过。)
事实上,您可以通过asking it to强制Python进入实习字符串。这将为您提供大量的性能提升并可能有所帮助。它可能没用。
道德:不要将is
与字符串文字一起使用。或者是int literals。或者在任何你不理解的地方,真的。
答案 1 :(得分:12)
要理解这一点,您需要了解一些不同的事情。
a is b
和a
是同一个对象,则b
会返回true,而不仅仅是具有相同的值。字符串可以具有相同的值,但可以是该值的不同实例。a = "x"
时,您实际在做的是创建字符串常量"x"
,然后为其指定名称a
。 String 常量是在代码中按字面写入的字符串,不是以编程方式计算的。字符串常量总是 interned ,这意味着它们存储在表中以供重用:如果你说a = "a"; b = "a"
,它实际上与说a = "a"; b = a
相同,因为它们会使用相同的实习字符串"a"
。这就是第一个a is b
为真的原因。a = "x" * 2
时,Python编译器实际上正在优化它。它在编译时计算字符串 - 它生成代码,就好像编写了a = "xx"
一样。因此,结果字符串"xx'
被实现。这就是为什么第二个a is b
是真的。a = "x" * n
时,Python编译器在编译时不知道n是。因此,它必须实际输出字符串"x"
,然后在运行时执行字符串乘法。由于这是在运行时执行的,而在"x"
被实习期间,结果字符串"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
最后,请注意,如果字符串可以保证a = intern(a); b = intern(b)
为真,则可以说a is b
创建实习版本。但是,如果您只想检查字符串相等性,请使用a == b
。