(Note: this is an off-topic side thread, unrelated to assignment expressions. Inline comment below.)
On Fri, May 11, 2018 at 9:08 AM, Chris Angelico <[email protected]> wrote: > On Fri, May 11, 2018 at 9:15 PM, Nick Coghlan <[email protected]> wrote: > > * *maybe* discover that even the above expansion isn't quite accurate, > and > > that the underlying semantic equivalent is actually this (one way to > > discover this by accident is to have a name error in the outermost > iterable > > expression): > > > > def _genexp(_outermost_iter): > > for x in _outermost_iter: > > yield x > > > > _result = _genexp(_outermost_iter) > > > > * and then realise that the optimised list comprehension form is > essentially > > this: > > > > def _listcomp(_outermost_iter): > > result = [] > > for x in _outermost_iter: > > result.append(x) > > return result > > > > _result = _listcomp(data) > > > > Now that "yield" in comprehensions has been prohibited, you've learned > all > > the edge cases at that point > > Not quite! You missed one, just because comprehensions aren't weird > enough yet. AFAIK you can't tell with the list comp, but with the > genexp you can (by not iterating over it). > > > def _genexp(_outermost_iter): > > for x in _outermost_iter: > > yield x > > > > _result = _genexp(data) > > It's actually this: > > def _genexp(_outermost_iter): > for x in _outermost_iter: > yield x > > _result = _genexp(iter(_outermost_iter)) > > I don't think there's anything in the main documentation that actually > says this, although PEP 289 mentions it in the detaily bits. [1] > > ChrisA > > [1] https://www.python.org/dev/peps/pep-0289/#the-details > I'm not sure this is the whole story. I tried to figure out how often __iter__ is called in a genexpr. I found that indeed I see iter() is called as soon as the generator is brought to life, but it is *not* called a second time the first time you call next(). However the translation you show has a 'for' loop which is supposed to call iter() again. So how is this done? It seems the generated bytecode isn't equivalent to a for-loop, it's equivalent to s while loop that just calls next(). Disassembly of a regular generator: def foo(a): for x in a: yield x * 2 0 SETUP_LOOP 18 (to 20)* 2 LOAD_FAST 0 (a) * 4 GET_ITER* >> 6 FOR_ITER 10 (to 18) 8 STORE_FAST 1 (x) 10 LOAD_FAST 1 (x) 12 YIELD_VALUE 14 POP_TOP 16 JUMP_ABSOLUTE 6 >> 18 POP_BLOCK >> 20 LOAD_CONST 0 (None) 22 RETURN_VALUE But for a generator: g = (x for x in C()) 1 0 LOAD_FAST 0 (.0) >> 2 FOR_ITER 10 (to 14) 4 STORE_FAST 1 (x) 6 LOAD_FAST 1 (x) 8 YIELD_VALUE 10 POP_TOP 12 JUMP_ABSOLUTE 2 >> 14 LOAD_CONST 0 (None) 16 RETURN_VALUE Note the lack of SETUP_LOOP and GET_ITER (but otherwise they are identical). -- --Guido van Rossum (python.org/~guido)
_______________________________________________ Python-ideas mailing list [email protected] https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
