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
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)