views:

292

answers:

5

I'm doing a complicated hack in Python, it's a problem when you mix for+lambda+*args (don't do this at home kids), the boring details can be omited, the unique solution I found to resolve the problem is to pass the lambda object into the self lambda in this way:

for ...
    lambda x=x, *y: foo(x, y, <selflambda>)

It's possible?, thanks a lot.

A: 

If you want to refer to it, you'll have to give it a name

bar=lambda x=x, *y: foo(x, y, bar)

such is the way of the snake

gnibbler
This definition grants the power of flowing through the Child-like Empress. However, be warned, you may only use this with Her permission. Tu, was du willst.
piggles
This does not work, because the for loop gives unconsistency to the variable naming.
mkotechno
+2  A: 

While your question is genuinely weird, try something like:

>>> import functools
>>> f = lambda selflambda, x=x, *y: foo(x, y, selflambda)
>>> f = functools.partial(f, f)
Antoine P.
This sounds good! answer flag for now
mkotechno
I'm glad this works for you, but it doesn't do what you asked for. This creates a second function that has a reference to the *first* function, *not* a reference to itself. The two functions behave differently and have different arguments.
Jason Orendorff
+6  A: 

You are looking for a fixed-point combinator, like the Z combinator, for which Wikipedia gives this Python implementation:

Z = lambda f: (lambda x: f(lambda *args: x(x)(*args)))(lambda x: f(lambda *args: x(x)(*args)))

Z takes one argument, a function describing the function you want, and builds and returns that function.

The function you're looking to build is:

Z(lambda f: lambda x=x, *y: foo(x, y, f))
Jason Orendorff
A: 

The easiest way is to write a separate function to create the lambda.

def mkfun(foo, x):
    f = lambda x=x, *y: foo(x, y, f)
    return f

for ...:
    ...mkfun(foo, x)...

This works just like gnibbler's suggestion but can be used in a for loop.

EDIT: I wasn't joking. It really works!

def foo(x, y, bar):
    print x
    if y:
        bar()  # call the lambda. it should just print x again.

# --- gnibbler's answer
funs = []
for x in range(5):
    bar=lambda x=x, *y: foo(x, y, bar)  # What does bar refer to?
    funs.append(bar)
funs[2](2, True)  # prints 2 4 -- oops! Where did the 4 come from?

# --- this answer
def mkfun(x, foo):
    bar = lambda x=x, *y: foo(x, y, bar)  # different bar variable each time
    return bar
funs = []
for x in range(5):
    funs.append(mkfun(x, foo))
funs[2](2, True)  # prints 2 2
Jason Orendorff
If a lambda is simply an anonymous function, and this technique has to bind it to name, I would think it wouldn't need to use lambda, and is probably harder to read because of it.
Peter Hansen
A function with just a lambda operates exacty equal than a lamba, this resolves nothing.
mkotechno
mkotechno: Did you try it?
Jason Orendorff
Yes I try it and much more, finally functools.partial was the solution
mkotechno
A: 

I don't understand why you want to do this with lambda.

lambda: creates a function object that does not have a name

def: creates a function object that does have a name

a name: very useful for calling yourself

for ...
    def selflambda(x=x, *y):
        return foo(x, y, selflambda)
    ...

Doesn't this do exactly what you requested? I even called it selflambda. If it doesn't do what you want, would you please explain why it doesn't?

EDIT: Okay, Jason Orendorff has pointed out that this won't work, because each time through the loop, the name selflambda will be rebound to a new function, so all the function objects will try to call the newest version of the function. I'll leave this up for the educational value, not because it is a good answer.

steveha
steveha: Look closely. What does the `selflambda` in that function refer to after the next loop iteration?
Jason Orendorff
Hmmm. Okay, so that is why the answer he accepted involves `functional.partial()`. I'll update my answer.
steveha