On Thu, Jul 22, 2010 at 5:48 PM, Carl M. Johnson firstname.lastname@example.org wrote:
On Wed, Jul 21, 2010 at 6:34 PM, Chris Rebert email@example.com wrote:
funcs =  for i in range(5): def f(i=i): print("#", i) funcs.append(f)
They're all non-obvious idioms, but at least this one is short and easily recognized.
I actually had to read that twice before I recognized what you had done, and I knew to look for something out of the ordinary. That said, it *is* the solution GvR recommended as the best solution the last time this came up. I just never understood why. To me, if you set something as a default value for an argument, it should be because it’s a default value, ie. a value that is usually one thing but can also be set to something else at the caller’s discretion. I’m just not comfortable with using the default value to mean “here’s a value you should never change” or “pretty please, don’t pass in an argument, because that will screw everything up” or even “I guess you could pass in an argument if you wanted to, but that’s not a case I’m really very busy thinking about". :-/ But maybe I’m in the minority on this one.
There's a reason that particular trick is called the "default argument hack" :)
The trick is much easier to follow when you *don't* reuse the variable name in the inner function:
funcs =  for i in range(5): def f(early_bound_i=i): print("#", early_bound_i) funcs.append(f)
Python doesn't really have a good way to request early binding semantics at this time - the default argument hack is about it.
The given clause (as currently specified in the PEP) forces early binding semantics on any functions it contains, so it allows you to write a function definition loop that "does the right thing" with the following fairly straightforward code:
funcs =  for i in range(5): funcs.append(f) given: def f(): print("#", i)
That's: a) kinda cool b) veering dangerously close to DWIM* territory (which is not necessarily a good thing)
Still, the early binding semantics angle is one I had thought about before - that *is* a genuinely new feature of this proposal. Perhaps not a hugely compelling one though - I think I've only needed to use the default argument hack once in the whole time I've been programming Python.
*Don't Worry It's Magic