12

I did quite a bit of perusing, but I don't have a definite answer for the concept that I'm trying to understand.

In Python, if I take a list, such as:

L1=['muffins', 'brownies','cookies']

And then attempted to replace the first pointer to an object in the list, namely 'muffins' by using the code:

L1[0:1] = 'cake'

I would get a list L1:

['c', 'a', 'k', 'e', 'brownies', 'cookies']

Yet if I took the same list and performed the operation (now with the 4 elements from the string cake):

L1[0:4] = ['cake'] # presumably, it's now passing the string cake within a list? (it passed into the modified list shown above)

I get the output I initially desired:

['cake', 'brownies', 'cookies']

Can anyone explain why that is, exactly? I'm assuming that when I take cake initially without it being in a "list", it breaks the string into its individual characters to be stored as references to those characters as opposed to a single reference to a string...

But I'm not entirely sure.

Noc
  • 519
  • 7
  • 18
  • 1
    Your last example `L1[0:4] = ['cake']` yields `['cake']` for me, not `['cake', 'brownies', 'cookies']` on python 2.6. -- Also note that since you already have 5 upvotes, apparently you asked a pretty good question :) – mgilson Jun 05 '12 at 18:26
  • 1
    Ah, the last example was with respect to the code that had already been modified - as in, instead of using: 'L1=['muffins', 'brownies','cookies']', I was performing the last example with 'L1 = ['c', 'a', 'k', 'e', 'brownies', 'cookies']'. – Noc Jun 06 '12 at 18:37

3 Answers3

16

Two important points:

  1. Slice assignment takes an iterable on the right-hand side, and replaces the elements of the slice with the objects produced by the iterable.
  2. In Python, strings are iterable: iterating over a string yields its characters.

Thus

L1[0:1] = 'cake'

replaces the first element of L1 with the individual characters of 'cake'.

To replace the first element with the string 'cake', simply write:

L1[0] = 'cake'

or, using the slice assignment syntax:

L1[0:1] = ['cake']
NPE
  • 486,780
  • 108
  • 951
  • 1,012
8

If you specify a slice, the righthand side is presumed to be a list/tuple (actually, any iterable - but watch out for generators that produce an indefinite number of values).

To replace an item in a list, use:

my_list[0] = "cake"

(You could also do

my_list[0:1] = ["cake"]

if you really want to use a list slice.

See also: slice assignment

Art Swri
  • 2,799
  • 3
  • 25
  • 36
  • 1
    @Levon - thanks for saying something nice! I really like your profile BTW - can I copy / restate it for mine? I'm pretty sick of the yah-yah attitude I see in the answers. I try to answer with just enough info to help the person, targeted at what I perceive is their level (and interest). – Art Swri Jun 05 '12 at 18:36
  • 1
    Sure, go ahead, glad I'm not the only one who notices the attitude of some members. And I totally agree, I try to tailor responses to the OP's level too .. no point showing off Python prowess if the question is very basic. Better to help with a solid basic answer and save the fancy stuff for more advanced questions :) .. having said that, this was a good question and got an upvote from me too. – Levon Jun 05 '12 at 18:40
  • the relevant refs points to same ref https://stackoverflow.com/questions/10623302/how-does-assignment-work-with-list-slices which one is the missing ?? – pippo1980 Feb 08 '23 at 22:25
3

Think of strings as being a sequence container that stores characters. When you try to do assignments that way, it adds each item in the character sequence to the list. By wrapping "cake" in its own 1-element list first (let's call it L2), you're instead adding each element of L2 to L1 -- it does not recursively split up sequence containers beyond the outermost sequence.

L1 = ['muffins', 'brownies','cookies']
L2 = ['cake']
L1[0:1] = L2
print L1
['cake', 'brownies', 'cookies']

This is also true for other nested sequence objects. Try experimenting with more nested sequence objects like this:

L3 = [['pie', 'eclairs'], ['bacon', 'chocolate']]
L1[0:1] = L3
print L1
[['pie', 'eclairs'], ['bacon', 'chocolate'], 'brownies', 'cookies']

It's also worth noting that if you don't care about order/positioning in the list, you can use append() and not have to worry about your string getting split up:

L1 = ['muffins', 'brownies','cookies']
L1.append('cake')
print L1
['muffins', 'brownies', 'cookies', 'cake']
Joe Baker
  • 235
  • 1
  • 8