I see at many places the use of slice assignment for lists. I am able to understand its use when used with (non-default) indices, but I am not able to understand its use like:
a_list[:] = ['foo', 'bar']
How is that different from
a_list = ['foo', 'bar']
?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
a_list = ['foo', 'bar']
Creates a new list in memory and points the name a_list at it. It is irrelevant what a_list pointed at before.
a_list[:] = ['foo', 'bar']
Calls the __setitem__ method of the a_list object with a slice as the index, and a new list created in memory as the value.
__setitem__ evaluates the slice to figure out what indexes it represents, and calls iter on the value it was passed. It then iterates over the object, setting each index within the range specified by the slice to the next value from the object. For lists, if the range specified by the slice is not the same length as the iterable, the list is resized. This allows you to do a number of interesting things, like delete sections of a list:
a_list[:] = [] # deletes all the items in the list, equivalent to 'del a_list[:]'
or inserting new values in the middle of a list:
a_list[1:1] = [1, 2, 3] # inserts the new values at index 1 in the list
However, with “extended slices”, where the step is not one, the iterable must be the correct length:
>>> lst = [1, 2, 3] >>> lst[::2] = [] Traceback (most recent call last): File "<interactive input>", line 1, in <module> ValueError: attempt to assign sequence of size 0 to extended slice of size 2
The main things that are different about slice assignment to a_list are:
a_listmust already point to an object- That object is modified, instead of pointing
a_listat a new object - That object must support
__setitem__with asliceindex - The object on the right must support iteration
- No name is pointed at the object on the right. If there are no other references to it (such as when it is a literal as in your example), it will be reference counted out of existence after the iteration is complete.
Method 2
The difference is quite huge! In
a_list[:] = ['foo', 'bar']
You modify a existing list that was bound to the name a_list. On the other hand,
a_list = ['foo', 'bar']
assigns a new list to the name a_list.
Maybe this will help:
a = a_list = ['foo', 'bar'] # another name for the same list a_list = ['x', 'y'] # reassigns the name a_list print a # still the original list a = a_list = ['foo', 'bar'] a_list[:] = ['x', 'y'] # changes the existing list bound to a print a # a changed too since you changed the object
Method 3
By assigning to a_list[:], a_list still reference to the same list object, with contents modified. By assigning to a_list, a_list now reference to a new list object.
Check out its id:
>>> a_list = [] >>> id(a_list) 32092040 >>> a_list[:] = ['foo', 'bar'] >>> id(a_list) 32092040 >>> a_list = ['foo', 'bar'] >>> id(a_list) 35465096
As you can see, its id doens’t change with the slice assignment version.
The different between the two could result quite different result, for instance, when the list is a parameter of function:
def foo(a_list):
a_list[:] = ['foo', 'bar']
a = ['original']
foo(a)
print(a)
With this, a is modified as well, but if a_list = ['foo', 'bar'] were used instead, a remains its original value.
Method 4
a_list = ['foo', 'bar'] a=a_list[:] # by this you get an exact copy of a_list print(a) a=[1,2,3] # even if you modify a it will not affect a_list print(a) print(a_list)
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0