Search code examples
pythonlambdalazy-evaluationlate-binding

lazy evaluation and late binding of python?


when is lazy evaluation? (generator, if, iterator?), when is late binding? (closure, regular functions?)

    a = [1,2,3,4]
    b = [lambda y: x for x in a] 
    c = (lambda y: x for x in a) #lazy evaluation
    d = map(lambda m: lambda y:m, a) #closure
    for i in b:
        print i(None)
    # 4 4 4 4
    for i in c:
        print i(None)
    # 1 2 3 4 
    for i in d:
        print i(None)
    # 1 2 3 4

Solution

  • This looks like homework, so I won't just give you the answers. Here are two functions that you can step through and see how the values change.

    def make_constants_like_generator():
        def make_constant(x):
            def inner(y):
                return x
            return inner
        results = []
        for i in [1, 2, 3, 4]:
            results.append(make_constant(i))
            for f in results:
                print f(None)
        return results
    
    def make_constants_like_list():
        x = None
        results = []
        for i in [1, 2, 3, 4]:
            x = i
            def inner(y)
                return x
            results.append(inner)
            for f in results:
                print f(None)
        return results
    

    Lazy evaluation is waiting until the last possible moment to evaluate an expression. The opposite is eager evaluation. The generator expression is lazy, it does nothing until it is iterated. The list expression is eager, as soon as it is encountered, the list is filled with values.

    Early and late binding relate to how the system determines what a name refers to. All names in python are late bound. Combined with lazy evaluation that means that what a name is bound to can change before expressions that use it are evaluated

    def map(func, iter):
        return (func(val) for val in iter)