Consider
l = [1, 2, 3, 4, 5]
print(l is l[:])
t = (1, 2, 3, 4, 5)
print(t is t[:])
print(t[1:] is t[1:])
print('aa'[1:] is 'aa'[1:])
print('aaa'[1:] is 'aaa'[1:])
The result is, somewhat surprisingly, False, True, False, True, False.
Additionally, if I create objects of types list, tuple and str with large lengths and then create large numbers of slices [1:] of each, only with str is it efficient in terms of time and memory, even though tuples are also immutable and could, just like strings, be represented without copying the range specified by a slice, just by indexing into the contiguous memory where the data is already stored.
Why does CPython behave this way? Is it an implementation thing, or are all implementations required to follow the same choices?
mylist[:]was the old idiom for creating a shallow copy (nowadays, I prefermylist.copy()for fluency reasons). I'm trying to find the actual documentation regardinglistobjects, but this is just a "well known fact" in Python that the semantics of slicinglistobjects impleis a copy. Note,memoryviewobjects creates new objects, but they share the underlying buffer!@repeated, rather thanarepeated, and I believe you will see different results.s.copy()creates a shallow copy of s (same ass[:])" but like I said, the assumption is thats[:]is known to create a copy! This idiom is probably as old as Python 1!isandid()can tell the difference.str, nortupleobjects (except copying the whole thing, for both types), just string interning. Bummer. It seems such a low hanging fruit.