Hacker News new | ask | show | jobs
by stevvooe 5663 days ago
Excellent explanation. I think most people's issue with python's lambda is that it isn't what they expect. There are generally some gotchas and the syntax diverges from that of a regular function.

I side step the lack of closures by using named locals with the keyword arguments when defining inner functions. However, for numeric types, this doesn't really work:

    def makeCounter():
        value = 0
        def count(value=value):
            tmp, value = value, value + 1
            return tmp
        return count

    inc = makeCounter()
    print inc()
    print inc()
The above prints '0\n0', but if we use an object that is used "by reference" in a such a function, one can get this behavior:

    def set_adder():
        s = set()
        def add(item, s=s):
            s.add(item)
            return s
        return add

    s = set_adder()
    print s(1)
    print s(2)

    t = set_adder()
    print t(3)
    print t(4)
This will print:

    $ python mk.py  
    set([1])  
    set([1, 2])
    set([3])
    set([3, 4])
1 comments

Python actually does have proper lexical scope and real closures (as of version 2.2, I think), so you can do

    def set_adder():
        s = set()
        def add(item):
            s.add(item)
            return s
        return add
and it'll work the same way. The problem really comes in the fact that before Python 3, all assignment took place in the local scope, so anything involving assignment (such as the counter example) doesn't work. You can sidestep it in Python 2.6 using the same kind of trick:

    def make_counter():
        value = [0]
        def count():
            temp, = value
            value[0] += 1
            return temp
        return count
which is sort of hacky but works. (Other languages sidestep this by having some other way of specifying declaration-versus-assignment, such as JavaScript's var keyword for variable declaration.)