how to write function that returns function

Bengt Richter bokr at oz.net
Fri May 17 23:01:28 EDT 2002


On 17 May 2002 15:28:06 -0700, spam at bugbear.com (Paul Graham) wrote:

>Thanks to several people who have sent me Python
>"translations" for the following:
>
>Scheme:  (define (foo x) 
>           (lambda (y) (set! x (+ x y))))
>
Ugly and not recommended, but as close as I've yet come:

 >>> def foo(x): return [lambda y:z.append(z.pop()+y) or z[0] for z in [[x]]][0]
 ...

It seems to work (unlike my previous misreading of incrementing by 1 instead of i
in another example).

 >>> f = foo(0)
 >>> f(0)
 0
 >>> [f(x) for x in xrange(10)]
 [0, 1, 3, 6, 10, 15, 21, 28, 36, 45]
 >>> [f(1) for x in xrange(10)]
 [46, 47, 48, 49, 50, 51, 52, 53, 54, 55]
 >>> [f(100) for x in xrange(10)]
 [155, 255, 355, 455, 555, 655, 755, 855, 955, 1055]
 
>Perl:    sub foo {
>           my ($n) = @_;
>           sub {$n += shift}
>         }
>
>Here is a summary of the answers I got.  This is
>the closest thing to a direct translation:
>
>def foo(n):
>  s = [n]
>  def bar(i):
>    s[0] += i
>    return s[0]
>  return bar
>
>but it is considered ugly, and the canonical way to
>do this seems to be by defining a class:
>
>class foo:
>  def __init__(self, n):
>      self.n = n
>
>  def __call__(self, i):
>      self.n += i
>      return self.n
>
Yes, it's much clearer. But I just thought of the following,
which seems to work, and seems to me also pretty clear:

 >>> def foo(n):
 ...     def bar(i):
 ...         bar.s += i
 ...         return bar.s
 ...     bar.s = n
 ...     return bar
 ...
 >>> f=foo(4)
 >>> f(3)
 7
 >>> f(10)
 17

The function bar is accessible via its own closure and thereby the attribute s.
So the attribute namespace seems to work like an assignable-within closure ;-)

BTW, is a function's appearing in its own closure a problem for the gc?

Regards,
Bengt Richter



More information about the Python-list mailing list