2

Is it possible in python to create an un-linked copy of a function? For example, if I have

a = lambda(x): x
b = lambda(x): a(x)+1

I want b(x) to always return x+1, regardless if a(x) is modified not. Currently, if I do

a = lambda(x): x
b = lambda(x): a(x)+1
print a(1.),b(1.)
a = lambda(x): x*0
print a(1.),b(1.)

the output is

1. 2.
0. 1.

Instead of being

1. 2.
0. 2.

as I would like to. Any idea on how to implement this? It seems that using deepcopy does not help for functions. Also keep in mind that a(x) is created externally and I can't change its definition. I've also looked into using this method, but it did not help.

Community
  • 1
  • 1
  • This is a very unusual question. How is the `a` function changing? What changes it? – Ned Batchelder Aug 13 '14 at 21:53
  • 1
    If you're worried about someone reassigning `a`, what if they just reassign `b`? – user2357112 Aug 13 '14 at 21:54
  • The main reason why a is changing is because it is located in a loop. For example: lambdas1 = [lambda(x): return x,lambda(x): return x*x] b = [] for i range(2): a = lambdas[i] b.append(lambda(x): a(x)+1) The problem is that each element of b is bounded to the definition of a. When i==1, the definition of a is changed, so is the definition of b[0]. – Olivier Soucy Aug 14 '14 at 17:46

2 Answers2

2

You could define b like this:

b = lambda x, a=a: a(x)+1

This makes a a parameter of b, and therefore a local variable. You default it to the value of a in the current environment, so b will hold onto that value. You don't need to copy a, just keep its current value, so that if a new value is created, you have the one you wanted.

That said, this sounds like something unusual happening, and if you tell us more about what's going on, there's likely a better answer.

Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
  • Exactly what I was looking for! In the mean time, I also found a similar answer [here](http://stackoverflow.com/questions/10452770/python-lambdas-binding-to-local-values) Thanks a lot! – Olivier Soucy Aug 14 '14 at 17:40
1

I might need to know a little more about your constraints before I can give a satisfactory answer. Why couldn't you do something like

a = lambda(x): x
c = a
b = lambda(x): c(x)+1

Then no matter what happens to a, b will stay the same. This works because of the somewhat unusual way that assignment works in Python. When you do c = a, the name c is linked to the object that a links to. You can use id() to look at that object's id and see that they are the same; c and a point to the same object.

c = a
id(a)
>>> 4410483968
id(c)
>>> 4410483968

Then, when you redefine a with a = lambda x: x*0, you're actually doing two things in one line. First, lambda x: x*0 creates a new function object, then the assignment causes the name a to be linked to the new object. As you can see, a is now pointing to a different object:

a = lambda x: x*0
id(a)
>>>> 4717817680

But if you look at id(c), it still points to the old object!

id(c)
>>>> 4410483968

This is because when we redefined a, we merely created a new object and linked a to it. c remains linked to the old one.

So if you redefine a as you do in the question, you get the output you want:

print a(1.),b(1.)
>>>> 0.0,2.0
Matt Adams
  • 709
  • 4
  • 11
  • Would be an even better answer IMHO if you explained _why_ or how it worked. – martineau Aug 13 '14 at 22:58
  • The problem remains the same. If c is changed somehow later in the execution, you definition of b will also change. It is problematic where you are trying to define b in a loop, while a (or c) is also part of that loop. @NedBatchelder provided a more suitable answer below. – Olivier Soucy Aug 14 '14 at 17:44