[Python-Dev] nested scopes confusion

Jeremy Hylton jeremy@zope.com
Tue, 4 Dec 2001 14:57:23 -0500 (EST)


> 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()

>>>>> "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.

>>> def functions():
... 	result = []
...	for i in range(10):
...		def wrap(i):
...			def mth(*args):
...				return i
...			return mth
...		result.append(wrap(i))
...	i = 25
...	return result
... 
>>> l = functions()
>>> l[0]()
0
>>> l[1]()
1

Jeremy