小编典典

Python:解释器中的id()行为

python

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

在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',但仍具有相同的标识符。


阅读 242

收藏
2021-01-20

共1个答案

小编典典

非常感谢@eryksun的更正!

这是由于interningPython中的机制调用:

在“
interned”字符串表中输入string并返回被中断的字符串–它是字符串本身或副本。插入字符串对于提高字典查找的性能很有用–如果字典中的键被插入,并且查找键被插入,则键比较(散列后)可以通过指针比较而不是字符串比较来完成。通常,Python程序中使用的名称会被自动插入,并且用于保存模块,类或实例属性的字典具有插入键。

在版本2.3中进行了更改:内联字符串不是不朽的(就像它们曾经在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仅插入没有空格的字符串,而不是因为我立即假定的长度:例如ASCII字母,数字和下划线。

2021-01-20