By jinhua luo via Discussions on Python.org at 27Mar2022 15:54:
Maybe this is the answer to my original question?
The slicing will create a new list (I check that the id()
is different), but copy the references of the corresponding elements of the original list to the new list. When I do the assignment to the element of the new list, it does not affect the original list, because it just overrides the element reference of the new list. So that’s why my recursive buddle sort failed.
Yes A list is just a list of references to objects (in your case, some
integers). A slice of a list gets you a new list, containing the
reeferences selected by the slice.
But when the whole list slice is at the left side of an assignment, the
right value is assigned to it in place, so it’s special. As well as
del lst[2:]
.
Yes. These are not copies of the list, they are a specification of some
range of elements in the list. So:
L[2:4] = [7,8,9]
is a specification of the elements with indices 2 and 3, to be replaced
with the elements from the new list on the right hand side of the
assignment:
>>> L=[1,2,3,4,5]
>>> L[2:4]=[7,8,9]
>>> L
[1, 2, 7, 8, 9, 5]
Likewise with del
, it is a specification of what to delete from the
list, like:
>>> del L[2:4]
>>> L
[1, 2, 9, 5]
If I undo that and use an assignment:
>>> L = [1, 2, 7, 8, 9, 5]
>>> L[2:4] = []
>>> L
[1, 2, 9, 5]
we get the same result, replacing elements with indices 2 and 3 with the
elements from an empty list.
Under the covers, these operations are mediated by special methods on
the list
class.
If you want to implement slicing in a class of your own, you can
implement these methods: __getitem__
, __setitem__
, __delitem__
.
You don’t even need to implement all of them!
So if you have some object L
then this:
L[2:4]
in an expression returns the result from this function call:
L.__getitem__( slice(2,4) )
“slice()” is a built in function to make a “slice” object:
>>> slice(2,4)
slice(2, 4, None)
so you can play with that directly. When you do:
L[2:4] = []
that calls:
L.__setitem__( slice(2,4), [] )
and:
del L[2:4]
calls:
L.__delitem__( slice(2,4) )
so what happens is actually up to the class definition. For a list
they do what you expect of a list
. By contrast, the expression:
L[2]
is the result of this function call:
L.__getitem__(2)
So like you might hope, all indexing goes through __getitem__
. It is
just that with L[2:4]
that function is passed a “slice” object instead
of an integer. The function has to decide what to do with it.
Why this digression? Because __getitem__
DOES NOT need to make a new
list
(or new “thing”, whatever class it is). Some classes might do
something else, meaningful for that class. For list
s, it does make a
new list
.
Cheers,
Cameron Simpson cs@cskk.id.au