Performance of list comprehensions vs. map

Alex Martelli aleax at aleax.it
Fri Sep 7 10:28:11 CEST 2001


"Chris Barker" <chrishbarker at home.net> wrote in message
news:3B981539.6126C949 at home.net...
    ...
> What about the input list? If I call a:
>
> l2 = map(function, l1)
>
> and another thread is altering l1 at the same time, will that effect l2?

Definitely!  It would be horrible for map to take a snapshot "behind
your back" of l1 -- it's trivially easy for YOU to explicitly make
a temporary copy, just map(function, l1[:]), if you want that, while,
if map violated all normal Pythonic expectations by taking a snapshot,
it would be very hard for you to get back to normal Pythonic behavior.

There doesn't have to be any threading involved for the effect
to surface...:

>>> l1=range(10)
>>> def function(x):
...     return x+l1.pop()
...
>>> map(function,l1)
[9, 9, 9, 9, 9]
>>> l1=range(10)
>>> map(function,l1[:])
[9, 9, 9, 9, 9, 9, 9, 9, 9, 9]

As function modifies global modifiable object l1, it makes a
big difference whether map is using l1 itself or a snapshot
copy thereof.  If you want a copy, ask for a copy -- exactly
as you would, e.g., in a for loop whose body may need to
modify the sequence on which the for is looping, you then
wouldn't write:
    for x in thelist:
        maychange(x,thelist)
but rather:
    for x in thelist[:]:
        maychange(x,thelist)
or, for maximum clarity/explicitness:
    for x in copy.copy(thelist):
        maychange(x,thelist)

> This is what is scary to me.

I don't really understand why.  It's *normal* to take a
copy/snapshot of a modifiable container in a threaded
environment, so you can release locks fast AND not have
the container change behind your back -- and here you
don't even need the locking since thelist[:] is atomic.
(It's less normal to have a function modify global
state, as it ain't in general good programming practice,
but we all fall from grace from time to time, no?-).


> >I suggested threads as a
> > way that object bindings could change during the execution of a chunk of
> > code, but the example above demonstrates it just as well without using
> > threads.
>
> well, it demonstrates re-binding of the generating function, not the
> source list being altered.. the later I find a lot more scary, and can't
> imagine how it could happen in a single thread.

Let's not confuse *re-binding* of the sequence (which would have no effect
on any of map, filter, reduce, list comprehension, for loops - each
takes a *reference* to the sequence at the start, of course) with
*alteration* (modification) of the sequence object.


Alex






More information about the Python-list mailing list