
At 04:30 PM 10/21/03 -0700, Guido van Rossum wrote:
Actually, I consider Samuele's example a good argument in *favor* of the idea. Because of the similarity between listcomps and generator expressions (gen-X's? ;) ) it seems late binding of locals would lead to people thinking the behavior is a bug. Since a genex is not a function (at least in form) a late binding would be very non-obvious and counterintuitive relative to other kinds of expressions.
Hm. We do late binding of globals. Why shouldn't we do late binding of locals?
Wha? Oh, you mean in a function. But that's what I'm saying, it's *not* a function. Sure, it's implemented as one under the hood, but it doesn't *look* like a function. In any normal (non-lambda) expression, whether a variable is local or global, its value is retrieved immediately. Also, even though there's a function under the hood, that function is *called* and its value returned immediately. This seems consistent with an immediate binding of parameters.
There are lots of corners or the language where if you expect something else the actual behavior feels like a bug, until someone explains it to you. That's no reason to compromise. It's an opportunity for education about scopes!
So far, I haven't seen you say any reason why the "arguments" approach is bad, or why the "closure" approach is good. Both are certainly Pythonic in some circumstances, but why do you feel that one is better than the other, here? I will state one pragmatic reason for using the default arguments approach: code converted from using a listcomp to a genex can immediately have bugs as a result of rebinding a local. Those bugs won't happen if rebinding the local has no effect on the genex's evaluation. (Obviously, an aliasing problem can still be created if one modifies a mutable used in the genex, but there's no way to remove that possibility and still end up with a lazy iterator.) Given that one of the big arguments in favor of genexes is to make "upgrading" from listcomps easy, it shouldn't fail so quickly and obviously. E.g., converting from: x = {} for i in range(10): x[i] = [y^i for y in range(10)] to: x = {} for i in range(10): x[i] = (y^i for y in range(10)) Shouldn't result in all of x's elements iterating over the same values!