In the python 3 documentation, str.replace is described as:
str.replace(old, new[, count])
Return a copy of the string with all occurrences of substring old replaced by new. If the optional argument count is given, only the first count occurrences are replaced.
According to this, the code
old = [['z','b']]
new = []
new.append(old[0])
print(old == new)
new[0][0] = old[0][0].replace('z','a')
print([old,new,old==new])
should return
True
[[['z', 'b']], [['a', 'b']], False]
However, in both python 2 and 3 it actually returns:
True
[[['a', 'b']], [['a', 'b']], True]
meaning that old has been modified from [['z','b']] to [['a', 'b']] even though the documentation implies it shouldn't. However, it's not that the documentation was poorly worded. The value of old is not changed every time. It depends on how we define the variable new. If we define new in a different but (seemingly) equivalent way:
old = [['z','b']]
new = [['z','b']]
print(old == new)
new[0][0] = old[0][0].replace('z','a')
print([old,new,old==new])
we get the output:
True
[[['z', 'b']], [['a', 'b']], False]
which is what we expected in the first place. In both cases, before the str.replace is used, old == new evaluates to True. Yet, depending on the method used to set the variable new to [['z','b']], str.replace changes the value of old.
How does Python "remember" how the variable new is defined, and change its output accordingly? How does Python know that there is something different between the two equivalent new variables? Regardless, why is the value of old changing at all? Shouldn't str.replace just return a modified copy of old instead of actually changing it?