【问题标题】:How python memory manage string object? [duplicate]python内存如何管理字符串对象? [复制]
【发布时间】:2020-02-16 07:09:44
【问题描述】:
for count in range(5):
    str1 = 'a' * count
    str2 = 'a' * count
    print(id(str1) == id(str2))

Output:
    True
    True
    False
    False
    False      

为什么我们会得到 False,因为

str1 = 'aaa'
str2 = 'aaa'
print(id(str1) == id(str2)) # True 

任何人解释一下这个 python 内存行为。

【问题讨论】:

  • 为什么重要?如果要测试字符串是否相等,请使用 == 运算符。这里发生的是某种可能特定于 CPython 的内存使用优化
  • 谢谢,但是 CPython 正在做哪种类型的内存优化,知道吗?
  • 我也很好奇这个问题。由于 str1 和 str2 是不同的字符串,它们不应该有不同的 ID 吗?还是因为它们指向同一个东西,所以它们具有相同的内存地址?
  • 这也发生在不超过256的整数中。可能是某种优化,没什么大不了的。

标签: python python-3.x cpython


【解决方案1】:

让我们首先调查id() 的作用:

返回对象的“身份”。这是一个整数,保证在其生命周期内对于该对象是唯一且恒定的。生命周期不重叠的两个对象可能具有相同的 id() 值。

CPython 实现细节:这是对象在内存中的地址。

好的,所以,一般来说,当两个名称指向完全相同的对象时,它们将具有相同的id()。

那我们为什么会有这个呢?

str1 = 'aaa'
str2 = 'aaa'
print(id(str1) == id(str2)) # True

这是因为,在CPython(Python 的 C 参考实现)中,字符串被缓存在哈希表中(出于性能原因),使用 str1 和 str2 指向同一内存更便宜. 请注意,这可以在没有太多意外行为的情况下完成,因为字符串在 Python 中是不可变的。 但是,此机制仅对 appear in full in the interpreter 的字符串触发,例如:

for i in range(5):
    a = eval('"' + 'a' * i + '"')
    b = eval('"' + 'a' * i + '"')
    print(id(a) == id(b), a, b)
True  
True a a
True aa aa
True aaa aaa
True aaaa aaaa

任何在解释器中动态创建str 的机制(即除了eval())都在此缓存之外,例如您的示例,或者:

a = 'aaa'
b = a[1:]
c = 'aa'
print(id(b) == id(c))
# False
print(id(b) == id(a[1:]))
# False

为了进一步参考,Python 中字符串的内部表示在PEP 393 中有更详细的描述。

【讨论】:

  • 这确实是一个非常好的答案!关于 Python 中的一般引用可能值得注意一点(例如 a = '456' 和 b = '456' 将指向同一个指针,而 a = 456 和 b = 456 不会)。
  • 对于ints,这会一直触发到256
  • @norok2 我了解字符串实习生和缓存,但我仍然不完全了解原始循环。为什么从第 3 次迭代开始,它们的评估结果为 false?
  • @CathaCronin 不,短路发生在代码中任何位置的任何字符串的s * 0 或s * 1。这两个操作不是生成动态字符串,而是分别获取指向空字符串和 s 本身的指针。
  • stackoverflow.com/q/24245324/5769463 @CathaCronin 简而言之:如果发生常量折叠(长度为 1 的字符串的情况),则字符串在编译时被保留,但对于在运行时创建的字符串(其他情况)则不会
猜你喜欢
  • 1970-01-01
  • 2011-12-24
  • 2016-03-10
  • 2010-10-11
  • 2011-10-22
  • 2018-12-20
  • 1970-01-01
  • 1970-01-01
  • 2021-07-28
相关资源
最近更新 更多