Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

L[:]

72 views
Skip to first unread message

Albert-Jan Roskam

unread,
Jan 10, 2014, 12:38:27 PM1/10/14
to Python
In Python Cookbook, one of the authors (I forgot who) consistently used the "L[:]" idiom like below. If the second line simply starts with "L =" (so no "[:]") only the name "L" would be rebound, not the underlying object. That was the authorś explanation as far as I can remember. I do not get that. Why is the "L[:]" idiom more memory-efficient here? How could the increased efficiency be demonstrated?

#Python 2.7.3 (default, Sep 26 2013, 16:38:10) [GCC 4.7.2] on linux2
>>> L = [x ** 2 for x in range(10)]
>>> L[:] = ["foo_" + str(x) for x in L]


Thanks!


Regards,

Albert-Jan



~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

All right, but apart from the sanitation, the medicine, education, wine, public order, irrigation, roads, a

fresh water system, and public health, what have the Romans ever done for us?

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Ned Batchelder

unread,
Jan 10, 2014, 5:03:49 PM1/10/14
to pytho...@python.org
On 1/10/14 12:38 PM, Albert-Jan Roskam wrote:
> In Python Cookbook, one of the authors (I forgot who) consistently used the "L[:]" idiom like below. If the second line simply starts with "L =" (so no "[:]") only the name "L" would be rebound, not the underlying object. That was the authorś explanation as far as I can remember. I do not get that. Why is the "L[:]" idiom more memory-efficient here? How could the increased efficiency be demonstrated?
>
> #Python 2.7.3 (default, Sep 26 2013, 16:38:10) [GCC 4.7.2] on linux2
>>>> L = [x ** 2 for x in range(10)]
>>>> L[:] = ["foo_" + str(x) for x in L]
>

I'm not sure there is a memory efficiency argument to make here. The
big difference is that the first line make L refer to a completely new
list, while the second line replaces the contents of an existing list.
This makes a big difference if there are other names referring to the list:

>>> L = [1, 2, 3, 4]
>>> L2 = L
>>> L[:] = []
>>> print L2
[]

>>> L = [1, 2, 3, 4]
>>> L2 = L
>>> L = []
>>> print L2
[1, 2, 3, 4]

Names and values in Python can be confusing. Here's an explanation of
the mechanics: http://nedbatchelder.com/text/names.html

HTH,

--Ned.

>
> Thanks!
>
>
> Regards,
>
> Albert-Jan



--
Ned Batchelder, http://nedbatchelder.com

Terry Reedy

unread,
Jan 10, 2014, 5:38:42 PM1/10/14
to pytho...@python.org
On 1/10/2014 12:38 PM, Albert-Jan Roskam wrote:
> In Python Cookbook, one of the authors (I forgot who) consistently used the "L[:]" idiom like below. If the second line simply starts with "L =" (so no "[:]") only the name "L" would be rebound, not the underlying object. That was the authorś explanation as far as I can remember. I do not get that. Why is the "L[:]" idiom more memory-efficient here? How could the increased efficiency be demonstrated?
>
> #Python 2.7.3 (default, Sep 26 2013, 16:38:10) [GCC 4.7.2] on linux2
>>>> L = [x ** 2 for x in range(10)]
>>>> L[:] = ["foo_" + str(x) for x in L]

Unless L is aliased, this is silly code. The list comp makes a new list
object, so if L does not have aliases, it would be best to rebind 'L' to
the existing list object instead of copying it. To do the replacement
'in place':
L = [x ** 2 for x in range(10)]
for i, n in enumerate(L):
L[i] = "foo_" + str(n)
print(L)
>>>
['foo_0', 'foo_1', 'foo_4', 'foo_9', 'foo_16', 'foo_25', 'foo_36',
'foo_49', 'foo_64', 'foo_81']
--
Terry Jan Reedy


Grant Edwards

unread,
Jan 11, 2014, 11:34:11 AM1/11/14
to
On 2014-01-10, Terry Reedy <tjr...@udel.edu> wrote:
> On 1/10/2014 12:38 PM, Albert-Jan Roskam wrote:
>> In Python Cookbook, one of the authors (I forgot who) consistently used the "L[:]" idiom like below. If the second line simply starts with "L =" (so no "[:]") only the name "L" would be rebound, not the underlying object. That was the author?? explanation as far as I can remember. I do not get that. Why is the "L[:]" idiom more memory-efficient here? How could the increased efficiency be demonstrated?
>>
>> #Python 2.7.3 (default, Sep 26 2013, 16:38:10) [GCC 4.7.2] on linux2
>>>>> L = [x ** 2 for x in range(10)]
>>>>> L[:] = ["foo_" + str(x) for x in L]
>
> Unless L is aliased, this is silly code.

And if L _is_ aliaised, it's probably trying to be too clever and
needs to be fixed.

--
Grant



Laszlo Nagy

unread,
Jan 13, 2014, 4:00:46 AM1/13/14
to pytho...@python.org

> Unless L is aliased, this is silly code.
There is another use case. If you intend to modify a list within a for
loop that goes over the same list, then you need to iterate over a copy.
And this cannot be called an "alias" because it has no name:

for idx,item in enumerate(L[:]):
# do something with L here, including modification



--
This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.

Terry Reedy

unread,
Jan 13, 2014, 3:23:17 PM1/13/14
to pytho...@python.org
On 1/13/2014 4:00 AM, Laszlo Nagy wrote:
>
>> Unless L is aliased, this is silly code.
> There is another use case. If you intend to modify a list within a for
> loop that goes over the same list, then you need to iterate over a copy.
> And this cannot be called an "alias" because it has no name:

for i in somelist: creates a second reference to somelist that somewhere
in the loop code has a name, so it is effectively an 'alias'. The
essential point is that there are two access paths to the same object.

> for idx,item in enumerate(L[:]):
> # do something with L here, including modification

The copy is only needed in the above if one inserts or deletes. But if
one inserts or deletes more than one item, one nearly always does better
to iterate through the original and construct a new list with new items
added and old items not copied.

--
Terry Jan Reedy

Albert-Jan Roskam

unread,
Jan 14, 2014, 5:42:07 AM1/14/14
to pytho...@python.org, Terry Reedy
====> Hi, first, thank you all for your replies -much appreciated!
Terry, this would be making a shallow copy, right? If so, then "list(L)" is slightly nicer IMHO, but that's probably a matter of taste (however, I don't like copy.copy, even though that's perhaps most clear --oh well nitpicking ;-)

I also found that item assignment ([1] below) is much faster than using the more standard (I think) .append ([2]).
# [1]
for idx,item in enumerate(L[:]):
if some_condition:
L[idx] = foobarify(item)
# [2]
L2 = []
for idx,item in enumerate(L):
if some_condition:
L2.append(foobarify(item))
else:
L2.append(item)


Terry Reedy

unread,
Jan 14, 2014, 5:07:15 PM1/14/14
to pytho...@python.org
On 1/14/2014 5:42 AM, Albert-Jan Roskam wrote:

> I also found that item assignment ([1] below) is much faster
> than using the more standard (I think) .append ([2]).

> # [1]
> for idx,item in enumerate(L[:]):
> if some_condition:
> L[idx] = foobarify(item)

[1] *is* the standard way to selectively replace items.

> # [2]
> L2 = []
> for idx,item in enumerate(L):
> if some_condition:
> L2.append(foobarify(item))
> else:
> L2.append(item)

--
Terry Jan Reedy

0 new messages