Htechno
Htechno

Reputation: 6127

Lambda, calling itself into the lambda definition

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.

Upvotes: 3

Views: 876

Answers (5)

steveha
steveha

Reputation: 76715

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.

Upvotes: 0

Jason Orendorff
Jason Orendorff

Reputation: 45116

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

Upvotes: 0

Jason Orendorff
Jason Orendorff

Reputation: 45116

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

Upvotes: 8

Antoine P.
Antoine P.

Reputation: 4315

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)

Upvotes: 4

John La Rooy
John La Rooy

Reputation: 304255

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

Upvotes: 0

Related Questions