x[0], y[0], z[0] 在cpython中内存地址是一样的,为什么a不是呢?

x[0], y[0], z[0] has the same memory address in cpython, but why a is not?

(env) λ python
Python 3.9.1 (tags/v3.9.1:1e5d33e, Dec  7 2020, 17:08:21) [MSC v.1927 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> x = ["test t", 2, 3]
>>> y = x
>>> z = x[:]
>>> x, y, z
(['test t', 2, 3], ['test t', 2, 3], ['test t', 2, 3])
>>> id(x[0]), id(y[0]), id(z[0])
(2818792500464, 2818792500464, 2818792500464)
>>> a = "test t"
>>> id(a)
2818792500720

我对python中的字符串常量池和字符串interning略知一二,为什么python让新定义的字符串的内存地址包含空白等特殊字符space 不同。

Python中的字符串是不可变的,这意味着字符串一旦创建就无法更改。当您创建一个字符串时,如果您创建相同的字符串并将其分配给另一个变量,它们将指向相同的 string/memory。例如,

>>> a = 'hi'
>>> b = 'hi'
>>> id(a)
437068484
>>> id(b)
437068484

这种字符串对象的重用在 Python 中称为驻留。相同的字符串具有相同的 ID。但是 Python 不能保证实习生字符串。如果您创建的字符串不是代码对象常量或包含 字母 + 数字 + 下划线 [=35 之外的字符=] 范围,你会看到 id() 值没有被重用。

我们改变给定字符串的id如下。我们将它分配给两个不同的标识符。发现时这些变量的 id 是不同的。这是因为给定的字符串包含字母、数字和下划线以外的字符。

>>> a = 'test_#@$'
>>> b = 'test_#@$'
>>> id(a)
962262086
>>> id(b)
917208009

现在看你的例子:

x[0], y[0], z[0] 是同一个对象,因为当您创建 x = ["test t", 2, 3] 时,您开始通过别名将引用传递给 yz

现在用另一个例子来说明更多: 创建一个具有相同值的列表,并为其创建一个别名,它们将具有相同的 ID。

>>> a = [1,2,3]
>>> b = a
>>> id(a)
1984438821696
>>> id(b)
1984438821696

但是当您创建两个等效列表时,它们与之前的列表并不相同。

>>> a = [1,2,3]
>>> b = [1,2,3]
>>> id(a)
1984438821696
>>> id(b)
1984438822336