
I would have expected the following code to print 1, 2, ..., 9. Instead it prints 25, 25, 25, .. 25. def functions(): result = [] for i in range(10): def mth(*args): return i result.append(mth) i = 25 return result for mth in functions(): print mth() Reading PEP227, I can (barely) understand why it behaves this way. How do I achieve the desired effect? Note that the default argument trick (def mth(i=i): ...) does not work because *args is present. Thomas

Yes, you're out of luck. Like in all decent languages with nested scope, Python binds to the variable, not to its value at the time the inner function is defined.
How do I achieve the desired effect? Note that the default argument trick (def mth(i=i): ...) does not work because *args is present.
Use a class with a __call__ method: class mth: def __init__(self, i): self.i = i def __call__(self, *args): return self.i and use: result.append(mth(i)) --Guido van Rossum (home page: http://www.python.org/~guido/)

"TH" == Thomas Heller <thomas.heller@ion-tof.com> writes:
TH> That's what I was trying to avoid, because it is too slow. Calling a regular method on an instance is about 5x faster than calling an instance that defines an __call__(). But the performance characteristics of class vs. function is really the bottleneck of your application? Are you sure that nested fuctions are really cheaper? Jeremy

"TH" == Thomas Heller <thomas.heller@ion-tof.com> writes:
TH> Calling a.test() takes 3.3 microseconds, and c.test() takes 3.16 TH> microseconds. So I 5% difference, based on a single set of measurements with one compiler/platform/etc., is enough to go out of your way to avoid classes? That seems conceivable for some very small set of applications, but not in general. Jeremy

So nested scopes are not really an alternative (at least in this case) to the 'lambda self, i=i: i' trick.
In this case, they aren't. In many other cases (e.g. when the variable from the outer scope is self), nobody will assign to this variable, in which case this does exactly the same thing as the i=i trick. Regards, Martin

From: "Thomas Heller" <thomas.heller@ion-tof.com>
def functions(): result = [] for i in range(10): def make_function(index): def mth(): return index return mth mth = make_function(i) result.append(mth) i = 25 return result for mth in functions(): print mth() But how will I understand this 3 months from now? Thomas

What's the problem with understanding this code? It looks totally clear to me. You could add a few comments or use more fancyful function names. --Guido van Rossum (home page: http://www.python.org/~guido/)

Thomas Heller wrote:
Why do you put the function definitions *inside* the functions() constructor ? AFAICTL the confusion is caused by this overly complicated nesting which doesn't seem necessary. -- Marc-Andre Lemburg CEO eGenix.com Software GmbH ______________________________________________________________________ Consulting & Company: http://www.egenix.com/ Python Software: http://www.lemburg.com/python/

"TH" == Thomas Heller <thomas.heller@ion-tof.com> writes:
TH> Reading PEP227, I can (barely) understand why it behaves this TH> way. It behaves this way because the reference to i in mth() uses the binding for i introduced in functions(). The important point here is that the binding is used, but i can be bound to different values at different times. The function mth() sees the value that i is bound to when it is called. In your example, mth() isn't called until after the loop finishes executing. TH> How do I achieve the desired effect? Note that the default TH> argument trick (def mth(i=i): ...) does not work because *args TH> is present. All sorts of ways, I imagine. You could use a class: class MthClass: def __init__(self, val): self.val = val def mth(self, *args): return self.val This version is probably immediately obvious to the reader. You could add an extra layer of functions, but this looks like a pretty obscure use of nested scopes to me.
Jeremy

Yes, you're out of luck. Like in all decent languages with nested scope, Python binds to the variable, not to its value at the time the inner function is defined.
How do I achieve the desired effect? Note that the default argument trick (def mth(i=i): ...) does not work because *args is present.
Use a class with a __call__ method: class mth: def __init__(self, i): self.i = i def __call__(self, *args): return self.i and use: result.append(mth(i)) --Guido van Rossum (home page: http://www.python.org/~guido/)

"TH" == Thomas Heller <thomas.heller@ion-tof.com> writes:
TH> That's what I was trying to avoid, because it is too slow. Calling a regular method on an instance is about 5x faster than calling an instance that defines an __call__(). But the performance characteristics of class vs. function is really the bottleneck of your application? Are you sure that nested fuctions are really cheaper? Jeremy

"TH" == Thomas Heller <thomas.heller@ion-tof.com> writes:
TH> Calling a.test() takes 3.3 microseconds, and c.test() takes 3.16 TH> microseconds. So I 5% difference, based on a single set of measurements with one compiler/platform/etc., is enough to go out of your way to avoid classes? That seems conceivable for some very small set of applications, but not in general. Jeremy

So nested scopes are not really an alternative (at least in this case) to the 'lambda self, i=i: i' trick.
In this case, they aren't. In many other cases (e.g. when the variable from the outer scope is self), nobody will assign to this variable, in which case this does exactly the same thing as the i=i trick. Regards, Martin

From: "Thomas Heller" <thomas.heller@ion-tof.com>
def functions(): result = [] for i in range(10): def make_function(index): def mth(): return index return mth mth = make_function(i) result.append(mth) i = 25 return result for mth in functions(): print mth() But how will I understand this 3 months from now? Thomas

What's the problem with understanding this code? It looks totally clear to me. You could add a few comments or use more fancyful function names. --Guido van Rossum (home page: http://www.python.org/~guido/)

Thomas Heller wrote:
Why do you put the function definitions *inside* the functions() constructor ? AFAICTL the confusion is caused by this overly complicated nesting which doesn't seem necessary. -- Marc-Andre Lemburg CEO eGenix.com Software GmbH ______________________________________________________________________ Consulting & Company: http://www.egenix.com/ Python Software: http://www.lemburg.com/python/

"TH" == Thomas Heller <thomas.heller@ion-tof.com> writes:
TH> Reading PEP227, I can (barely) understand why it behaves this TH> way. It behaves this way because the reference to i in mth() uses the binding for i introduced in functions(). The important point here is that the binding is used, but i can be bound to different values at different times. The function mth() sees the value that i is bound to when it is called. In your example, mth() isn't called until after the loop finishes executing. TH> How do I achieve the desired effect? Note that the default TH> argument trick (def mth(i=i): ...) does not work because *args TH> is present. All sorts of ways, I imagine. You could use a class: class MthClass: def __init__(self, val): self.val = val def mth(self, *args): return self.val This version is probably immediately obvious to the reader. You could add an extra layer of functions, but this looks like a pretty obscure use of nested scopes to me.
Jeremy
participants (6)
-
Guido van Rossum
-
Jeremy Hylton
-
jeremy@zope.com
-
M.-A. Lemburg
-
Martin v. Loewis
-
Thomas Heller