[Python-ideas] while conditional in list comprehension ??

Wolfgang Maier wolfgang.maier at biologie.uni-freiburg.de
Tue Jan 29 16:24:55 CET 2013


yoav glazner <yoavglazner at ...> writes:
> > Here is very similar version that works (tested on python27)
> >>>> def stop():
> > next(iter([]))
> >
> >>>> list((i if i<50 else stop()) for i in range(100))
> > [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
> > 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
> > 40, 41, 42, 43, 44, 45, 46, 47, 48, 49]

Joao S. O. Bueno <jsbueno at ...> writes:
> Great. I think this nails it. It is exactly the intended behavior,
> and very readable under current language capabilities.
>> One does not have to stop and go read what "itertools.takewhile" does,
> and mentally unfold the lambda guard expression - that is what makes
> this (and the O.P. request) more readable than using takewhile.
>> Note: stop can also just explictly raise StopIteration -
> or your next(iter([])) expression can be inlined within the generator.
>> It works in Python 3 as well - though for those who did not test:
> it won't work for list, dicr or set comprehensions - just for
> generator expressions.
>
Shane Green <shane at ...> writes:
>> Here's what I was doing, and worked when i switched to the generator: 
>> >>> def stop(): 
> … raise StopIteration()
>>> >>> list(((x if x < 5 else stop()) for x in range(10)))
> [0, 1, 2, 3, 4]

Wow, thanks to the three of you!
I think it's still not as clear what the code does as it would be with my
'while' suggestion. Particularly, the fact that this is not a simple 'if'-or-not
decision for individual elements of the list, but in fact terminates the list
with the first non-matching element (the while-like property) can easily be
overlooked.
However, I find it much more appealing to use built-in python semantics than to
resort to the also hard to read itertools.takewhile().
In addition, this is also the fastest solution that was brought up so far. In my
hands, it runs about 2x as fast as the equivalent takewhile construct, which in
turn is just marginally faster than Boris Borcic's suggestion:
|>>> def notyet(cond) :
	if cond :
		raise StopIteration
	return True
|>>> list(x for x in range(100) if notyet(x>10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
I guess, I'll use your solution in my code from now on.
Best,
Wolfgang


More information about the Python-ideas mailing list

AltStyle によって変換されたページ (->オリジナル) /