fogbit
fogbit

Reputation: 2063

Generator and actual variable values

I need to write a function which returns an list of sum functions, adding an input number to some binded value. This is what i did:

def addition_range(start, end):
    if start >= end: return None

    #res = ( (lambda x: x + i) for i in range(start, end) ) #1
    res = [ (lambda x: x + i) for i in range(start, end) ] #2

    return res

for i in addition_range(0, 5): print( i(2) )

The output should be like: 2,3,4,5,6 but it's 6,6,6,6,6

The problem is in "i" variable, when i call the functions, they use actual value of i (4), not value used during generation of the list. The problem could be simply solved by using (#1) instead (#2), but i'm interested is there a solution for (#2)? I tried

res = [ (lambda x: x + copy.deepcopy(i)) for i in range(start, end) ]

but it doesn't help.

Thank you.

WinXP + Python 3.2

Upvotes: 0

Views: 71

Answers (1)

Sven Marnach
Sven Marnach

Reputation: 601599

The easiest way to solve this is by adding a dummy parameter:

def addition_range(start, end):
    res = [(lambda x, i=i: x + i) for i in range(start, end)]
    return res or None

The dummy parameter is evaluated at the time the lambda is defined, whereas your version evaluates i only when the lambda is called.

Side note: I added the or None part only to simulate the exact behaviour of your implementation. It would probably be better to return an empty list instead of None:

def addition_range(start, end):
    return [(lambda x, i=i: x + i) for i in range(start, end)]

Upvotes: 1

Related Questions