Python 中的可变和不可变

2024-01-02

我是 Python 新手,试图理解可变对象和不可变对象之间的区别。 Python 中的可变类型之一是列表。假设 L = [1,2,3],那么 L 有一个指向对象 [1,2,3] 的 id。如果[1,2,3]的内容被修改,那么L仍然保留相同的id。换句话说,即使对象的大小和内容已经改变,L 仍然与同一个对象相关联。

对于不可变对象,我的理解是不允许修改对象。因此,如果为变量重新分配新值,则该变量将绑定到具有不同 id 的新对象。我希望字符串以类似的方式表现。然而我尝试修改一个字符串,但字符串 id 没有改变。

string = "blue"
for i in range(10):
    string = string + str(i)
    print("string id after {}th iteration: {}".format(i,id(string)))


string id after 0th iteration: 46958272
string id after 1th iteration: 46958272
string id after 2th iteration: 46958272
string id after 3th iteration: 47077400
string id after 4th iteration: 47077400
string id after 5th iteration: 47077400
string id after 6th iteration: 47077400
string id after 7th iteration: 47077400
string id after 8th iteration: 47077400
string id after 9th iteration: 47077400

你确实不应该连续两次看到相同的 ID,但 CPython 对字符串连接进行了优化+这并没有完全遵守它应该遵守的所有规则。

当 CPython 看到以下形式的操作时x = x + something or x += something, if x指的是一个字符串并且x持有only引用该字符串,然后 CPython 将使用以下命令来增长该字符串realloc而不是创建一个新的字符串对象。根据可用内存的详细信息,realloc可能会调整已分配内存的大小,也可能会分配新内存。如果它调整分配大小,则该对象的id保持不变。你可以看到实现unicode_concatenate https://github.com/python/cpython/blob/v3.7.3/Python/ceval.c#L5006 in Python/ceval.c.

这个优化是mostly很好,因为引用计数检查确保它的行为mostly就好像字符串确实是不可变的并且创建了一个新字符串。然而,在x = x + stuff,旧字符串和新字符串should具有短暂重叠的生命周期,因为新字符串应该在赋值结束旧字符串的生命周期之前存在,所以它shouldID 值不可能相等。

id这是优化与没有发生字符串突变时明显不同的少数方式之一。语言开发者似乎已经决定他们对此表示同意。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python 中的可变和不可变 的相关文章

随机推荐