Fun fact: At least in CPython, strings are technically not immutable (although for all practical purposes they are). This is due to an optimization made for string addition.
If you do a:
string = string + stringtwo
and the reference count of string before the operation is one, then CPython reuses string instead of allocating a new memory location. You can check this by doing id(string) before and after the operation.
Even when CPython does find cases when it reuses the same memory location, it's still creating a new object rather than mutating the old one, I'd say. But using the same memory address. It's all academic as this won't make any difference in practice, but I'd most definitely classify strings as an immutable type!
Yes, to clarify, whether it decides to create a new object or reuse the existing object depends on several factors. However, we can see this if we iteratively add:
> Even when CPython does find cases when it reuses the same memory location, it's still creating a new object rather than mutating the old one.. It's all academic as this won't make any difference in practice, but I'd most definitely classify strings as an immutable type!
In practice, since it only does this when the ref count is one, it's the same as strings being immutable. I just find this corner case very fascinating.
Fun fact: At least in CPython, strings are technically not immutable (although for all practical purposes they are). This is due to an optimization made for string addition.
If you do a:
string = string + stringtwo
and the reference count of string before the operation is one, then CPython reuses string instead of allocating a new memory location. You can check this by doing id(string) before and after the operation.
But:
```
name = "hello"
print(id(name))
# 4378810272
name = name + "bye"
print(id(name))
# 4379196848
```
This is 3.12
Even when CPython does find cases when it reuses the same memory location, it's still creating a new object rather than mutating the old one, I'd say. But using the same memory address. It's all academic as this won't make any difference in practice, but I'd most definitely classify strings as an immutable type!
Yes, to clarify, whether it decides to create a new object or reuse the existing object depends on several factors. However, we can see this if we iteratively add:
>>> import collections
>>> letters = ['h', 'e','l', 'l','o',' ', 'w','o','r','l','d']
>>> ids = []
>>> string = ''
>>> for letter in letters:
... string = string + letter
... ids.append(id(string))
...
>>> print(collections.Counter(ids))
Counter({1601851586912: 3, 1601851587056: 3, 1601850291696: 2, 140723900781096: 1, 1601850286128: 1, 1601850284272: 1})
> Even when CPython does find cases when it reuses the same memory location, it's still creating a new object rather than mutating the old one.. It's all academic as this won't make any difference in practice, but I'd most definitely classify strings as an immutable type!
Not exactly. It's indeed mutating the old object. https://github.com/python/cpython/blob/3.12/Objects/unicodeobject.c#L10943-L10948
In practice, since it only does this when the ref count is one, it's the same as strings being immutable. I just find this corner case very fascinating.