About
RSS

No Let-over-Lambda in Python 2 :(


Standard idiom in LISP (or in this case, Scheme), Let over Lambda (also the title of an impressive book on LISP macros by Doug Hoyte):


(define (mkcounter) 
	(let ((n 0)) 
		(lambda () (begin 
			(set! n (+ 1 n))
			n))))

What does it do? It returns a function that returns 1, 2, 3, ... when called repeatedly. It's a way of keeping state in a world of functions. Don't confuse it with C's static Variables inside functions. mkcounter constructs a new counter object for each invocation, so


(define c1 (mkcounter))
(define c2 (mkcounter))
(c1) (c1) (c1) (c2)
(print (c1))
(print (c2))

would print 4 2.

An attempt to reconstruct this in Python 2.x:


def mkcounter():
        n = 0
        def _inner_():
                n = n+1
                return n
        return _inner_
c1=mkcounter()
print c1()

fails with UnboundLocalError: local variable 'n' referenced before assignment, which is somewhat confusing, since n is visible in _inner_ if the n = n+1 line is removed.
The impossibility of LoL in Python has been pointed out in PEP-3104 but was only fixed in Python 3. In Python 3 it's possible to reconstruct LoL by the dubiously named nonlocal directive:


def mkcounter():
    n = 0
    def _inner_():
            nonlocal n
            n = n + 1
            return n
    return _inner_

c1=mkcounter()
print(c1())

Mon, 15 Jul 2013
[/projects] permanent link