需要澄清 Python 中字符串的不变性
Clarification needed regarding immutability of strings in Python
字符串在 Python 中是不可变的,但在下面的示例中,一旦我开始将字母连接到初始字符串,就会生成一个新的 ID,这个 ID 将保持不变,直到我将一个新字符串分配给同名 reversedString。根据我对不可变性的理解,在每个连接中都必须分配新的 id,因为字符串是不可变的,不像列表。请澄清相同。
sample = "hello"
print(id(sample)) # 1635882773744
sample += "A"
print(id(sample)) # 1635885488752
sample += "D2"
print(id(sample)) # 1635885488752
sample += "EWWW"
print(id(sample)) # 1635885488752
sample = "R"
print(id(sample)) # 1635795667504
输出:
1635882773744
1635885488752
1635885488752
1635885488752
1635795667504
在 CPython 中,id 与字符串在内存中的存储位置有关。它不表示任何有关可变性的信息。具体如何使用内存是一个内部实现细节。您当然可以深入研究 CPython 内存管理的内部结构以解开 in-depth,但这并不是很有用。 (Im) 可变性可以简单地证明:
>>> foo = 'bar'
>>> baz = foo
>>> id(foo), id(baz)
(4402654512, 4402654512)
>>> foo += 'quux'
>>> print(foo, baz)
barquux bar
>>> foo[1] = 'o'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
使用 +=
改变 foo
不会改变 baz
,即使它们曾经指代同一个对象。通过订阅 (foo[1] = ...
) 直接更改字符不起作用并引发错误。这证明了字符串不变性。在执行期间如何为此分配内存并不重要。
id() 给出存储变量的地址。当然,每次更改该变量时都会发生变化。 id() 不会与您提到的相同。每次都会像说的那样变化。检查地址并不能说明您正在检查字符串的不变性。
有关字符串的更多说明,请检查以下内容 link:
https://www.python.org/dev/peps/pep-3137/
Python 解释器似乎有点聪明。它检测到变量 sample
的旧值正在被丢弃,并且它可以重新使用存储旧值的 space。因此,旧值和新值最终具有相同的 id()
,即使它们是不同的对象。
如果您将三个 sample += ...
中的每一个替换为
temp = sample
sample += ...
你会发现你每次都会得到不同的 id()
。我们正在阻止 Python 立即回收 space,因为另一个变量持有旧值。
字符串是不可变的。您无需“测试”它。一旦一个字符串明显死了,Python 就可以随心所欲地 re-use 它的 space 。你不能指望 id 在所有对象中都是唯一的,无论是活的还是死的。
字符串在 Python 中是不可变的,但在下面的示例中,一旦我开始将字母连接到初始字符串,就会生成一个新的 ID,这个 ID 将保持不变,直到我将一个新字符串分配给同名 reversedString。根据我对不可变性的理解,在每个连接中都必须分配新的 id,因为字符串是不可变的,不像列表。请澄清相同。
sample = "hello"
print(id(sample)) # 1635882773744
sample += "A"
print(id(sample)) # 1635885488752
sample += "D2"
print(id(sample)) # 1635885488752
sample += "EWWW"
print(id(sample)) # 1635885488752
sample = "R"
print(id(sample)) # 1635795667504
输出:
1635882773744
1635885488752
1635885488752
1635885488752
1635795667504
在 CPython 中,id 与字符串在内存中的存储位置有关。它不表示任何有关可变性的信息。具体如何使用内存是一个内部实现细节。您当然可以深入研究 CPython 内存管理的内部结构以解开 in-depth,但这并不是很有用。 (Im) 可变性可以简单地证明:
>>> foo = 'bar'
>>> baz = foo
>>> id(foo), id(baz)
(4402654512, 4402654512)
>>> foo += 'quux'
>>> print(foo, baz)
barquux bar
>>> foo[1] = 'o'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
使用 +=
改变 foo
不会改变 baz
,即使它们曾经指代同一个对象。通过订阅 (foo[1] = ...
) 直接更改字符不起作用并引发错误。这证明了字符串不变性。在执行期间如何为此分配内存并不重要。
id() 给出存储变量的地址。当然,每次更改该变量时都会发生变化。 id() 不会与您提到的相同。每次都会像说的那样变化。检查地址并不能说明您正在检查字符串的不变性。
有关字符串的更多说明,请检查以下内容 link: https://www.python.org/dev/peps/pep-3137/
Python 解释器似乎有点聪明。它检测到变量 sample
的旧值正在被丢弃,并且它可以重新使用存储旧值的 space。因此,旧值和新值最终具有相同的 id()
,即使它们是不同的对象。
如果您将三个 sample += ...
中的每一个替换为
temp = sample
sample += ...
你会发现你每次都会得到不同的 id()
。我们正在阻止 Python 立即回收 space,因为另一个变量持有旧值。
字符串是不可变的。您无需“测试”它。一旦一个字符串明显死了,Python 就可以随心所欲地 re-use 它的 space 。你不能指望 id 在所有对象中都是唯一的,无论是活的还是死的。