[Python-ideas] while conditional in list comprehension ??
Steven D'Aprano
steve at pearwood.info
Wed Jan 30 21:52:15 CET 2013
On 30/01/13 20:46, Wolfgang Maier wrote:
> b) I have to say I was very impressed by the speed gains you report through the
> use of 'partial', which I had not thought of at all, I have to admit.
> However, I tested your suggestions and I think they both suffer from the same
> mistake:
> your condition is 'partial(lt,50)', but this is not met to begin with and
> results in an empty list at least for me. Have you two actually checked the
> output of the code or have you just timed it? I found that in order to make it
> work the comparison has to be made via 'partial(gt,50)'.
Yes, you are absolutely correct. I screwed that up badly. I can only take comfort
that apparently so did Yuriy.
I don't often paste code in public without testing it, but when I do, it
invariably turns out to be wrong.
> With this modification
> the resulting list in your example would be [0,..,49] as it should be.
>
> And now the big surprise in terms of runtimes:
> partial(lt,50) variant: 1.17 (but incorrect results)
> partial(gt,50) variant: 13.95
> if cond or stop() variant: 9.86
I do not get such large differences. I get these:
py> min(t1.repeat(number=100000, repeat=5)) # cond or stop()
1.2582030296325684
py> min(t2.repeat(number=100000, repeat=5)) # takewhile and lambda
1.9907748699188232
py> min(t3.repeat(number=100000, repeat=5)) # takewhile and partial
1.8741891384124756
with the timers t1, t2, t3 as per my previous email.
> I guess python is just smart enough to recognize that it compares against a
> constant value all the time, and optimizes the code accordingly (after all the
> if clause is a pretty standard thing to use in a comprehension).
No, it is much simpler than that. partial(lt, 50) is equivalent to:
lambda x: lt(50, x)
which is equivalent to 50 < x, *not* x < 50 like I expected.
So the function tests 50 < 0 on the first iteration, which is False, and
takewhile immediately returns, giving you an empty list.
I was surprised that partial was *so much faster* than a regular function. But
it showed me what I expected/wanted to see, and so I didn't question it. A lesson
for us all.
> So the reason for your reported speed-gain is that you actually broke out of the
> comprehension at the very first element instead of going through the first 50!
Correct.
--
Steven
More information about the Python-ideas
mailing list