Newbie: list comprehension troubles..

Chris Rebert clp2 at rebertia.com
Sun Aug 23 20:52:47 EDT 2009


On Sun, Aug 23, 2009 at 5:09 PM, Ben Finney<ben+python at benfinney.id.au> wrote:
> Chris Rebert <clp2 at rebertia.com> writes:
>
>> tlist = [pair for pair in ((obj, obj.intersect(ray)) for obj in
>> self.objs) if pair[1] is not None]
>>
>> Should it be done? Probably not. [Compared to a ‘for’ suite with an
>> ‘if’ suite, it's] less readable and less efficient.
>
> I disagree on the “less efficient”, unless you've measured it. The
> Python compiler and machine make list comprehensions and generator
> expressions turn into quite efficient code.

Well, I hadn't benchmarked it originally, but since you bring it up:

class Foo(object):
    def __init__(self, n):
        self.n = n
    def intersect(self, ray):
        return ray + self.n

objs = [Foo(n) for n in range(300)]
ray = 42


def listcomp(objs, ray):
    tlist = [pair for pair in ((obj, obj.intersect(ray)) for obj in
objs) if pair[1] is not None]

def naive(objs, ray):
    tlist = []
    for obj in objs:
        t = obj.intersect(ray)
        if t is not None:
            tlist.append((obj,t))

chris at morpheus Desktop $ python
Python 2.6.2 (r262:71600, May 14 2009, 16:34:51)
[GCC 4.0.1 (Apple Inc. build 5484)] on darwin
chris at morpheus Desktop $ python -m timeit -n 10000 -s 'from tmp import
naive, ray, objs' 'naive(objs, ray)'
10000 loops, best of 3: 227 usec per loop
chris at morpheus Desktop $ python -m timeit -n 10000 -s 'from tmp import
listcomp, ray, objs' 'listcomp(objs, ray)'
10000 loops, best of 3: 254 usec per loop

The numbers for each test stayed within a few usec of each other over
a few runs. I thus conclude that the list comprehension method is
indeed slower (which makes sense looking at the 2 algorithms).

> I also disagree on “less readable”, if you show the structure and choose
> meaningful names (I can only guess at the meaning from the OP's code)::
>
>    tribbles = [
>        (obj, tribble) for (obj, tribble) in (
>            (obj, obj.intersect(ray))
>            for obj in self.objs)
>        if tribble is not None]

I do concede it becomes somewhat more readable if split over multiple lines:

pairs = ((obj, obj.intersect(ray)) for obj in self.objs)
tlist = [pair for pair in pairs if pair[1] is not None]

Cheers,
Chris
--
http://blog.rebertia.com



More information about the Python-list mailing list