supercheetah
supercheetah

Reputation: 3250

Why are my lambdas disappearing?

I have some Python code that's dependent upon passing around some lambdas, and they get copied to a few different places, but I'm finding that when I pop them out of a list, they just magically disappear from all the other lists. I don't know if this is a bug or not. I'll note that I'm running this on CPython.

Here's some code to illustrate my point:

a = lambda x: x+x*3
b = []
c = []

for i in range(3):
    b.append(a)

for i in range(3):
    c.append(b)

while b:
    print b.pop()(5)

for d in c:
    while d:
        print d.pop()(10)

If Python were doing reference counting, the new lists should increment the refcount, but the lambdas just keep disappearing.

I even tried this so that each time through the first loop a new instance of the lambda is created:

b = []
c = []

for i in range(3):
    b.append(lambda x: x+x*3)

for i in range(3):
    c.append(b)

while b:
    print b.pop()(5)

for d in c:
    while d:
        print d.pop()(10)

Still no go.

Anyone have a clue on what's happening here?

Upvotes: 1

Views: 179

Answers (3)

user395760
user395760

Reputation:

list.pop modifies the list in-place. So everyone with a reference to the list sees the same change. You're not storing copies in the second, you're just storing several references to one single list, which is then emptied in the first while loop.

You can copy lists through a[:] (which is a slice from the beginning to the end, including both) - note that it's a shallow copy - and nearly everything (including your own classes' instances) with the copy module.

Upvotes: 4

Tom
Tom

Reputation: 2016

import copy
for i in range(3):
    b.append(copy.deepcopy(a))
for i in range(3):
    c.append(copy.deepcopy(b))

You are only creating references (shallow copy), to truly copy the values like what you expect you must use a "deep copy".

Upvotes: 1

Tom Neyland
Tom Neyland

Reputation: 6968

The way you have your example setup, the only thing holding a reference to your lambdas is the list B. C holds a reference to list B not to the lambdas inside of B. When you pop the lambdas out of B, no references to the lambda remain. What you are left with is C with the references to B which is now empty.


Also, a good tip was pointed out in the comments of another answer:

Credit: Dfan

If you want to append a copy of b to c, you could say c.append(b[:])

Upvotes: 2

Related Questions