I want to know if slicing creates a copy of the list and if we use del over a slice. Then won't it create a copy, i.e. a new object from the list for a given slice first and then delete it?
So if a program is truly in-place then we cannot use slices.
# suppose if I use something like this:
a = [1,2,3,4,5,6,7,8,9,0]
del a[5:]
So, won't this del [a:]
create a copy of a
in the given slice a[5:]
and then delete it?
Is so, it won't be an in-place operation right as we are using slices here.
But
a = [1,2,3,4,5,6,7,8,9,0]
for i in range(5,len(a),-1):
del a[i]
This operation is in-place since we are not using slices.
So this should be faster right? Because we don't have to go through the pain of creating a new slice and directly deleting the object.
But I checked and it is the opposite:
%%timeit
a = [x for x in range(1000)]
del a[500:]
> 45.8 µs ± 3.05 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%%timeit
a = [x for x in range(1000)]
for i in range(999,499,-1):
del a[i]
> 92.9 µs ± 3.24 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Now, if we assume that del a[500:]
creates a slice first and then deletes, then it's not truly in-place, and using a for
loop for the same task is in-place?
But then why is the loop taking more time for the task?
Also, if in case, I assume that somehow they are both in-place and del a[500:]
does not creates a slice copy of a
at that index and del
directly goes at the index 500 and recursively deletes the elements, then what is exactly a[500:]
in this statement? Is it just to tell where should del
delete from?
If so, then is it not a slice?
I referred to a few links such as the one below to find an answer to this, but I am not very clear from any of the explanations exclusively focusing on in-place
operations.
The important thing to understand is that these are two different things:
del name
and
del container[index]
The first deletes a name from the current namespace. del
does not work with arbitrary expressions, and it does not delete objects, it delete names:
>>> del [1,2,3]
File "<stdin>", line 1
SyntaxError: cannot delete literal
>>> del list()
File "<stdin>", line 1
SyntaxError: cannot delete function call
However,
del container[index]
Will invoke
container.__delitem__(index)
Which can do whatever you want, it can be in-place or not. Or not do anything...
On the other hand
container[index]
Invokes
container.__getitem__(index)
Which, again, can do whatever you want. It can return a copy, or if you want to implement it that way, it can work in-place.
Perhaps, this is enlightening:
>>> class Container:
... def __getitem__(self, item):
... print('Container.__getitem__ called with', item)
... def __delitem__(self, item):
... print('Container.__delitem__ called with', item)
...
>>> container = Container()
>>> container[:]
Container.__getitem__ called with slice(None, None, None)
>>> del container[:]
Container.__delitem__ called with slice(None, None, None)
>>> del container
Note, del container
doesn't invoke either...