我是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
答案 0 :(得分:2)
您实际上不应该连续两次看到相同的ID,但是CPython对+
进行的字符串连接进行了优化,但并没有完全遵守应有的所有规则。
当CPython看到x = x + something
或x += something
形式的操作时,如果x
引用一个字符串,并且x
保留 only 引用到该字符串,则CPython将使用realloc
扩展字符串,而不是创建新的字符串对象。根据可用内存的详细信息,realloc
可能会在适当位置调整已分配内存的大小,也可能会分配新内存。如果它调整分配大小,则对象的id
保持不变。您可以在Python/ceval.c
的{{3}}中看到实现。
此优化主要是,因为refcount检查可确保其表现为主要是,就好像字符串实际上是不可变的,并且创建了新的字符串一样。但是,在x = x + stuff
中,旧字符串和新字符串应具有短暂重叠的生存期,因为新字符串应在赋值结束旧字符串的生存期之前就已存在,因此 ID值相等应该是。
id
是优化的显着不同于未发生字符串突变的几种方法之一。语言开发人员似乎已经决定对此表示满意。