Python:Interpreter中的id()行为

时间:2013-03-03 03:50:06

标签: python

我遇到了这种奇怪的行为,它只发生在交互式Python会话中,但是当我编写脚本并执行它时却没有。

String是Python中的不可变数据类型,因此:

>>> s2='string'
>>> s1='string'
>>> s1 is s2
True

现在,奇怪的部分:

>>> s1='a string'
>>> s2='a string'
>>> s1 is s2
False

我已经看到在字符串中有空格会导致这种行为。如果我把它放在一个脚本中并运行它,那么在两种情况下结果都是True。

有人会对此有所了解吗?感谢。

编辑:

好的,上面的问题和答案给出了一些想法。现在这是另一个实验:

>>> s2='astringbstring'
>>> s1='astringbstring'
>>> s1 is s2
True

在这种情况下,字符串肯定比'a string'长,但仍然具有相同的标识符。

1 个答案:

答案 0 :(得分:6)

非常感谢@eryksun的更正!

这是因为Python中的机制调用interning

  

在“interned”字符串表中输入字符串并返回   interned string - 字符串本身或副本。实习字符串   有用的是在字典查找上获得一点性能 - 如果   字典中的密钥被中断,查找密钥被中断,   密钥比较(散列后)可以通过指针比较来完成   而不是字符串比较。通常,Python中使用的名称   程序自动实习,字典用于保存   模块,类或实例属性具有实习键。

     

版本2.3中更改:Interned字符串不是不朽的(就像它们一样   曾经在Python 2.2及之前);你必须保留一个参考   返回intern()的值,从中受益。

CPython 将自动实习某些字符串(1个字母的字符串,关键字,没有分配空格的字符串)以提高查找速度和比较速度:例如, 'dog' is 'dog'将是指针比较,而不是完整的字符串比较。但是,对所有(较长)字符串的自动实习需要更多的内存,这并不总是可行的,因此它们可能不共享相同的标识,这使得id()的结果不同,例如:。

# different id when not assigned
In [146]: id('dog')
Out[146]: 4380547672

In [147]: id('dog')
Out[147]: 4380547552

# if assigned, the strings will be interned (though depends on implementation)
In [148]: a = 'dog'

In [149]: b = 'dog'

In [150]: id(a)
Out[150]: 4380547352

In [151]: id(b)
Out[151]: 4380547352

In [152]: a is b
Out[152]: True

对于整数,至少在我的机器上,CPython会自动实时自动实习256:

In [18]: id(256)
Out[18]: 140511109257408

In [19]: id(256)
Out[19]: 140511109257408

In [20]: id(257)
Out[20]: 140511112156576

In [21]: id(257)
Out[21]: 140511110188504

更新感谢@eryksun :在这种情况下,字符串'a string'不会因为CPython only interns strings without spaces而被实习,而不是因为我立即假设的长度:例如, ASCII字母,数字和下划线。

有关详细信息,您还可以参考Alex Martelli's answer here