10

我遇到了这种奇怪的行为,它只发生在交互式 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',但仍然具有相同的标识符。

4

1 回答 1

6

非常感谢@eryksun 的更正!

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

在“interned”字符串表中输入 string 并返回 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 字母、数字和下划线。

有关更多详细信息,您还可以在此处参考Alex Martelli 的回答

于 2013-03-03T03:54:54.007 回答