3

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.

Htechno
  • 5,901
  • 4
  • 27
  • 37
  • Duplicate: http://stackoverflow.com/questions/481692/can-a-lambda-function-call-itself-recursively-in-python – Li0liQ Jan 07 '10 at 22:08
  • I saw it, but I do not want to do recursion, and this solutions has a a lot ofuscation to do recursion... Some simplest solution? – Htechno Jan 07 '10 at 22:20
  • Without the boring details this appears to be little more than a decorator. Wouldn't that be simpler? – S.Lott Jan 07 '10 at 23:11

5 Answers5

8

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
  • 42,793
  • 6
  • 62
  • 96
4

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.
  • 4,181
  • 1
  • 24
  • 17
  • 1
    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 Jan 08 '10 at 16:02
0

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

John La Rooy
  • 295,403
  • 53
  • 369
  • 502
  • 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. – Ritwik Bose Jan 07 '10 at 22:44
  • 2
    This does not work, because the for loop gives unconsistency to the variable naming. – Htechno Jan 07 '10 at 23:12
0

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
  • 42,793
  • 6
  • 62
  • 96
  • 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 Jan 07 '10 at 23:39
  • 1
    A function with just a lambda operates exacty equal than a lamba, this resolves nothing. – Htechno Jan 07 '10 at 23:51
  • Yes I try it and much more, finally functools.partial was the solution – Htechno Jan 08 '10 at 15:08
0

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
  • 74,789
  • 21
  • 92
  • 117