Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Updating a sliced list

Tags:

python

list

I thought I understood Python slicing operations, but when I tried to update a sliced list, I got confused:

>>> foo = [1, 2, 3, 4]
>>> foo[:1] = ['one'] # OK, foo updated
>>> foo
['one', 2, 3, 4] 
>>> foo[:][1] = 'two' # why foo not updated?
>>> foo
['one', 2, 3, 4] 
>>> foo[:][2:] = ['three', 'four'] # Again, foo not updated
>>> foo
['one', 2, 3, 4] 

Why isn't foo updated after foo[:][1] = 'two'?

Update: Maybe I didn't explain my questions clearly. I know when slicing, a new list is created. My doubt is why a slicing assignment updates the list (e.g. foo[:1] = ['one']), but if there are two levels of slicing, it doesn't update the original list (e.g. foo[:][2:] = ['three', 'four']).

like image 280
Peng Li Avatar asked Jan 14 '16 08:01

Peng Li


People also ask

Does slicing a list create a new list?

In short, slicing is a flexible tool to build new lists out of an existing list. Python supports slice notation for any sequential data type like lists, strings, tuples, bytes, bytearrays, and ranges. Also, any new data structure can add its support as well.

What is the difference between slicing and indexing of list?

“Indexing” means referring to an element of an iterable by its position within the iterable. “Slicing” means getting a subset of elements from an iterable based on their indices.

Is slicing possible in list?

As well as using slicing to extract part of a list (i.e. a slice on the right hand sign of an equal sign), you can set the value of elements in a list by using a slice on the left hand side of an equal sign. In python terminology, this is because lists are mutable objects, while strings are immutable.

What is slice operation explain with an example?

Definition and UsageThe slice() function returns a slice object. A slice object is used to specify how to slice a sequence. You can specify where to start the slicing, and where to end. You can also specify the step, which allows you to e.g. slice only every other item.


3 Answers

foo[:] is a copy of foo. You mutated the copy.

like image 166
TigerhawkT3 Avatar answered Oct 07 '22 23:10

TigerhawkT3


This is because python does not have l-values that could be assigned. Instead, some expressions have an assignment form, which is different.

A foo[something] is a syntactic sugar for:

foo.__getitem__(something)

but a foo[something] = bar is a syntactic sugar for rather different:

foo.__setitem__(something, bar)

Where a slice is just a special case of something, so that foo[x:y] expands to

foo.__getitem__(slice(x, y, None))

and foo[x:y] = bar expands to

foo.__setitem__(slice(x, y, None), bar)

Now a __getitem__ with slice returns a new list that is a copy of the specified range, so modifying it does not affect the original array. And assigning works by the virtue of __setitem__ being a different method, that can simply do something else.

However the special assignment treatment applies only to the outermost operation. The constituents are normal expressions. So when you write

foo[:][1] = 'two'

it gets expanded to

foo.__getitem__(slice(None, None, None)).__setitem__(1, 'two')

the foo.__getitem__(slice(None, None, None)) part creates a copy and that copy is modified by the __setitem__. But not the original array.

like image 39
Jan Hudec Avatar answered Oct 07 '22 23:10

Jan Hudec


The main thing to notice here is that foo[:] will return a copy of itself and then the indexing [1] will be applied on the copied list that was returned

# indexing is applied on copied list
(foo[:])[1] = 'two'
    ^
copied list

You can view this if you retain a reference to the copied list. So, the foo[:][1] = 'two' operation can be re-written as:

foo = [1, 2, 3, 4]

# the following is similar to foo[:][1] = 'two'

copy_foo = foo[:]  
copy_foo[1] = 'two'

Now, copy_foo has been altered:

print(copy_foo)
# [1, 'two', 3, 4]

But, foo remains the same:

print(foo)
# [1, 2, 3, 4]

In your case, you didn't name the intermediate result from copying the foo list with foo[:], that is, you didn't keep a reference to it. After the assignment to 'two' is perfomed with foo[:][1] = 'two', the intermediate copied list ceases to exist.

like image 32
Dimitris Fasarakis Hilliard Avatar answered Oct 08 '22 00:10

Dimitris Fasarakis Hilliard