小能豆

关于python中字符串实例唯一性的问题

javascript

我试图找出哪些整数 python 只实例化一次(似乎是 -6 到 256),在此过程中偶然发现了一些我看不出模式的字符串行为。有时,以不同方式创建的相等字符串共享相同的 id,有时则不共享。此代码:

A = "10000"
B = "10000"
C = "100" + "00"
D = "%i"%10000
E = str(10000)
F = str(10000)
G = str(100) + "00"
H = "0".join(("10","00"))

for obj in (A,B,C,D,E,F,G,H):
    print obj, id(obj), obj is A

印刷:

10000 4959776 True
10000 4959776 True
10000 4959776 True
10000 4959776 True
10000 4959456 False
10000 4959488 False
10000 4959520 False
10000 4959680 False

我甚至看不出其中的规律——除了前四个没有显式的函数调用——但肯定不是这样,因为+例如 C 中的“”意味着对add 的函数调用。我尤其不明白为什么 C 和 G 不同,因为这意味着加法成分的 id 比结果更重要。

那么,AD 经历了什么特殊处理,使得它们成为同一个实例?


阅读 19

收藏
2024-11-04

共1个答案

小能豆

在 Python 中,字符串的行为可以部分归因于 字符串驻留(interning) 机制。驻留会导致某些字符串被“缓存”并重用以优化性能。这种缓存通常适用于短字符串和某些纯数字或标识符形式的字符串。驻留机制的具体行为在不同 Python 版本和实现中可能略有不同,但一般会应用在编译时确定的字符串常量上。

在您的示例中,Python 为一些字符串对象提供驻留,导致共享相同的 id,而其他字符串则没有被驻留,因此每个生成的字符串都分配了一个新的 id。具体分析如下:

  1. 直接赋值的字符串常量:像 AB,它们是字符串字面量 "10000",在 Python 编译时创建。这些字符串被驻留,所以 AB 指向相同的对象并共享相同的 id

  2. 拼接的字符串常量:对于 C ("100" + "00"),Python 在编译时就知道这两个字符串是常量,因此会将它们优化为一个单独的驻留字符串,这使得 C 也与 AB 指向相同的对象。

  3. 格式化和动态生成的字符串:例如 D ("%i" % 10000),以及通过 str() 函数创建的 EF,这些字符串是在运行时生成的,不会被驻留。由于没有驻留,它们在内存中创建了独立的对象,导致不同的 id

  4. 动态拼接的字符串:像 G (str(100) + "00") 和 H ("0".join(("10", "00"))) 也是在运行时生成的,因此不会被驻留,这意味着它们是新的对象并且拥有不同的 id

因此,关键区别在于:
- 编译时常量(如直接字面量或拼接的字面量)可能会被驻留,导致它们共享 id
- 运行时动态生成的字符串(例如使用 str()% 格式化、join 等)通常不会被驻留,每个生成的字符串是一个新的对象。

Python 的驻留规则对数字和标识符形式的字符串较为严格,因此并不是所有字符串都适用。对于更短的、简单的字符串,驻留机制更常见,而较长或动态创建的字符串则更少驻留。

2024-11-04