On Sat, Apr 21, 2018 at 05:46:44PM +1000, Chris Angelico wrote: > On Sat, Apr 21, 2018 at 5:11 PM, Steven D'Aprano <st...@pearwood.info> wrote:
> > So can you explain specifically what odd function-scope behaviour you > > are referring to? Give an example please? > > doubled_items = [x for x in (items := get_items()) if x * 2 in items] > > This will leak 'items' into the surrounding scope (but not 'x'). The "not x" part is odd, I agree, but it's a popular feature to have comprehensions run in a separate scope, so that's working as designed. The "leak items" part is the behaviour I desire, so that's not odd, it's sensible *wink* The reason I want items to "leak" into the surrounding scope is mostly so that the initial value for it can be set with a simple assignment outside the comprehension: items = (1, 2, 3) [ ... items := items*2 ... ] and the least magical way to do that is to just make items an ordinary local variable. > [x for x in x if x] # This works The oddity is that this does work, and there's no assignment expression in sight. Given that x is a local variable of the comprehension `for x in ...` it ought to raise UnboundLocalError, as the expanded equivalent does: def demo(): result = [] for x in x: # ought to raise UnboundLocalError if x: result.append(x) return result That the comprehension version runs (rather than raising) is surprising but I wouldn't call it a bug. Nor would I say it was a language guarantee that we have to emulate in similar expressions. In the absence of either explicit documentation of this behaviour, or Guido or one of the senior core developers explicitly stating that it is intentional behaviour that should be considered a language promise, I'd call it an accident of implementation. In which case, the fact that your next example: > [x for y in x if x := y] # UnboundLocalError "correctly" raises, as does the expanded version: def demo(): result = [] for y in x: # ought to raise UnboundLocalError x = y # since x is a local if x: result.append(x) return result shouldn't be seen as a problem. The code is different, so why should it behave the same? > (x for x in 5) # TypeError > (x for _ in [1] for x in 5) # Works Now that last one is more than just odd, it is downright bizarre. Or at least it would, if it did work: py> list((x for _ in [1] for x in 5)) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 1, in <genexpr> TypeError: 'int' object is not iterable Are you sure about this example? In any case, since this has no assignment expression in it, I don't see why it is relevant. -- Steve _______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com