def f(x):
return x
f = lambda : f(5)
f()
=> Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 4, in <lambda>
TypeError: <lambda>() takes 0 positional arguments but 1 was given
I can see intuitively why this doesn't work...it's sort of a circular reference. Specifically what rule in Python is it breaking?
CodePudding user response:
Well, you're overriding the function name. On the lambda
line:
f = lambda : f(5)
It becomes a recursion, it does f(5)
which calls itself. The only reason it didn't call it self over and over again (recursion) is because you're using lambda:
, that takes no arguments, so if you did:
f = lambda: f()
You would get a RecursionError
.
A lambda
is essentially a function, that lambda
could be translated to:
def f():
return f()
CodePudding user response:
The f
inside lambda: f(5)
is a free variable. (It is not defined in the scope of the function; it's value is found outside the function scope.) The current value of f
is not used to define the resulting function; the value of f
will be looked up when the function is called, and the value of f
can (and in this case does) change between the function being defined and the function being called.
When you finally call f()
, the value of f
is the same function, but now you attempt to call it with the argument that the original, not the current, function bound to the name f
expected, resulting in a TypeError
.
CodePudding user response:
In addition to what @U12-Forward posted, the reason you create a circular reference is the late binding of the lambda. By the time it calls f(5)
it's already referring to itself.
If your intent is to call your original f()
you can force the binding with:
f = lambda f=f: f(5)
and calling f()
will return 5
because that's what the original f()
does.