[Tutor] functions

Michael P. Reilly arcege@speakeasy.net
Tue, 29 Jan 2002 09:22:07 -0500


On Mon, Jan 28, 2002 at 07:49:12PM -0800, Kirby Urner wrote:
> You can return anything.  You can even return another
> function:
> 
>    >>> def f(x=3):
>            def g(y):
>               return y**x
>            return g
> 
>    >>> h = f(2)
>    >>> h
>    <function g at 0x0113B040>
>    >>> h(5)
>    25

A good explanation for the newbies, Kirby.

At the risk of confusing people that will only see Python 2.2 code,
and never really have to worry about reading through old stuff or
are not required to use an older release.  There is something missing
from this piece tho.

You might want to note that the above will break on earlier versions of
Python.  The g() function does not keep the "x" variable in Python 2.1,
in fact you get a syntax warning and a NameError exception being raised.

Python 2.1 (#1, Jun  1 2001, 19:52:18)
[GCC 2.96 20000731 (Red Hat Linux 7.0)] on linux2
Type "copyright", "credits" or "license" for more information.
>>> def f(x=3):
...   def g(y):
...     return y**x
...   return g
...
<stdin>:1: SyntaxWarning: local name 'x' in 'f' shadows use of 'x' as global in nested scope 'g'
>>> h = f(2)
>>> h(5)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<stdin>", line 3, in g
NameError: global name 'x' is not defined
>>>

You can get it to work in Python 2.1 by added 'from __future__ import
nested_scopes'.  But it won't work on releases earlier than that.  The
function would need to use the "default arguments" you mentioned.

Python 1.5.2 (#1, Aug 25 2000, 09:33:37)  [GCC 2.96 20000731 (experimental)] on linux-i386
Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
>>> def f(x=3):
...   def g(y, x=x):
...     return y**x
...   return g
...
>>> h = f(2)
>>> h(5)
25
>>>

The "x=x" takes the value from the f() function and puts it inside the
g() function.  Remember that functions follow the LGB rule.

The LGB namespace rule stands for Local-Global-Builtins.  It shows in
which namespace Python would find a variable: in the local namespace,
the global namespace (the module) or in __builtins__.  If a function
wants to carry a value from another function's local namespace, the new
function needs to explicitly hold the value, for example, by the default
arguments above.

Have fun.

  -Arcege