On 15 July 2013 22:34, Jan Kaliszewski <zuo@chopin.edu.pl> wrote:
15.07.2013 12:40, Oscar Benjamin wrote:
first_line = next(inputfile) # inspect first_line for line in chain([first_line], inputfile): # process line
could be rewritten as
first_line = next(inputfile): for line in first_line, *inputfile: pass
without reading the whole file into memory.
Please note, that with PEP 448 syntax you could express it by:
first_line = next(inputfile) for line in (*it for it in ([first_line], inputfile)): ...
I had realised that but I probably prefer chain() to the above. Thinking about it now what really bothers me about writing that kind of code is the need to trap StopIteration around calls to next() (or to supply and check for a default value). The chain part isn't so bad.
Event now, in Python 3.3, you can[*] write:
first_line = next(inputfile) for line in [(yield from it) for it in [[first_line], inputfile]]: ...
[*] Please note that it is `yield from` within a *list comprehension*, not a generator expression... And that this list cimprehension still evaluates to a *generator*, not a list! (a [None, None] list is set as StopIteration's value when the generator is exhausted)
Where exactly is the above defined/discussed? I looked through PEP 380 (yield from) but I can't find any mention of comprehensions or generator expressions. I guess that it unrolls as def _func(): tmp = [] for it in [[first_line], inputfile]: tmp.append(yield from it) # Now _func is a generator function return tmp # becomes raise StopIteration(tmp) for line in _func(): ... but I hadn't considered the fact that using yield from in the expression would turn a list comprehension into a generator function according to the unrolling logic. Oscar