奇怪的结果在python中

时间:2010-11-04 15:45:13

标签: python string identity

有人可以在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... ?

2 个答案:

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

第三个是因为编译器没有插入字符串ab,无论出于何种原因(可能是因为它不够聪明,没有注意到变量n是定义一次然后从未修改过。)

事实上,您可以通过asking it to强制Python进入实习字符串。这将为您提供大量的性能提升并可能有所帮助。它可能没用。

道德:不要将is与字符串文字一起使用。或者是int literals。或者在任何你不理解的地方,真的。

答案 1 :(得分:12)

要理解这一点,您需要了解一些不同的事情。

    如果a is ba 是同一个对象,则
  • 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