在什么情况下相等的字符串共享相同的引用?

问题描述 投票:0回答:3

我已经搜索了网络和堆栈溢出问题,但无法找到这个问题的答案。我的观察是,在 Python 2.7.3 中,如果您为两个变量分配相同的单个字符串,例如

>>> a = 'a'
>>> b = 'a'
>>> c = ' '
>>> d = ' '

然后变量将共享相同的引用:

>>> a is b
True
>>> c is d
True

对于一些较长的字符串也是如此:

>>> a = 'abc'
>>> b = 'abc'
>>> a is b
True
>>> '  ' is '  '
True
>>> ' ' * 1 is ' ' * 1
True

但是,在很多情况下,参考文献(意外地)未共享:

>>> a = 'a c'
>>> b = 'a c'
>>> a is b
False
>>> c = '  '
>>> d = '  '
>>> c is d
False
>>> ' ' * 2 is ' ' * 2
False

有人可以解释一下原因吗?

我怀疑解释器和/或某些缓存机制可能会进行简化/替换,这些机制利用了Python字符串在某些特殊情况下不可变的事实来进行优化,但我知道什么?我尝试使用 str 构造函数和 copy.deepcopy 函数制作字符串的深层副本,但字符串仍然不一致地共享引用。

我遇到问题的原因是因为我在为新型 python 类的克隆方法编写的一些单元测试中检查对字符串的引用是否不相等。

python string reference immutability
3个回答
9
投票

何时缓存和重用字符串的详细信息取决于实现,可能会因 Python 版本而异,并且不能依赖。如果您想检查字符串是否相等,请使用

==
,而不是
is

在 CPython(最常用的 Python 实现)中,字符串文字仅由 ASCII 字母、数字和下划线组成被保留,因此如果这样的字符串文字在源代码中出现两次,它们最终将指向相同的字符串对象。在 Python 2.x 中,您还可以调用内置函数

intern()
来强制保留特定字符串,但实际上您不应该这样做。

编辑关于检查属性是否在实例之间不正确共享的实际目的:这种检查仅对可变对象有用。对于不可变类型的属性,共享对象和非共享对象之间没有语义差异。您可以使用

从测试中排除不可变类型
Immutable = basestring, tuple, numbers.Number, frozenset
# ...
if not isinstance(x, Immutable):    # Exclude types known to be immutable

请注意,这也会排除包含可变对象的元组。如果您想测试这些,您需要递归地下降到元组。


5
投票

我认为这是一个实施和优化的事情。如果字符串很短,它们可以(并且经常?)“共享”,但你不能依赖于此。一旦你有了更长的字符串,你就会发现它们不一样。

In [2]: s1 = 'abc'
In [3]: s2 = 'abc'

In [4]: s1 is s2
Out[4]: True

更长的琴弦

In [5]: s1 = 'abc this is much longer'
In [6]: s2 = 'abc this is much longer'

In [7]: s1 is s2
Out[7]: False

使用

==
来比较字符串(而不是 is
 运算符)。

--

OP 的观察/假设(在下面的评论中)认为这可能是由于代币数量所致,似乎得到以下支持:

In [12]: s1 = 'a b c' In [13]: s2 = 'a b c' In [14]: s1 is s2 Out[14]: False

如果与上面

abc

的初始示例相比。


5
投票
在 CPython 中,作为实现细节

空字符串是共享的,代码点在 Latin-1 范围内的单字符字符串也是如此。您不应该依赖于此,因为可以绕过此功能。 您可以使用

sys.intern

请求将字符串interned;在某些情况下这会自动发生:


通常,Python 程序中使用的名称会自动驻留,并且用于保存模块、类或实例属性的字典具有驻留键。

sys.intern
已公开,以便您可以使用它(在分析之后!)来提高性能:

  
内部字符串对于在字典查找方面获得一点性能很有用 - 如果字典中的键被内部,并且查找键被内部,则可以通过指针比较而不是字符串比较来完成键比较(散列后)。

请注意,

intern

是Python 2中的内置函数。

    

© www.soinside.com 2019 - 2024. All rights reserved.