ZWang
ZWang

Reputation: 892

Python recursion error when multiplying functions

I'm using python 3 and trying to multiply functions within a for loop. I wrote a simple example code to demonstrate my problem. What I want this code to do was to start with the funciton x^2, then multiply it by x^2 in first loop, to get x^4. Then multiply x^4 again with x^2 to get x^6 e.t.c.

fun = lambda x: x**2

function = lambda x: x**2
for i in range(2):
    function = lambda x: function(x) * fun(x)

print(function(2))

But the code comes out with a Recursion error. I have no idea how this is causing a recursion though? Any help will be much appreciated.

Upvotes: 1

Views: 147

Answers (3)

cdlane
cdlane

Reputation: 41905

An alternate syntax: rather than pass a second argument to the lambda, you can use a nested lambda where the outer one is evaulated to return the inner one:

squared = lambda x: x**2
function = lambda x: x**2

for i in range(2):
    function = (lambda f: lambda x: f(x) * squared(x))(function)

print(function(2))

Just seems more generic solution (language-wise) than a defaulted argument.

Upvotes: 0

ZWang
ZWang

Reputation: 892

I never found a solution to this, but did find a workaround. Rather than trying to multiply it straight away, I wrote a function to do the multiplication. This seems to works so I'll just use this instead.

def multiplyFun(fun1,fun2):
    fun = lambda x: fun1(x) * fun2(x)
    return fun


fun = lambda x: x**2

function = lambda x: x**2
for i in range(5):
    print(i)
    function = multiplyFun(function,fun)

print(function(2))

Upvotes: 0

fzbd
fzbd

Reputation: 507

The assignment in your loop is equivalent to:

def function(x):
    return function(x) * fun(x)

Which is a recursive function without a stop condition. Your initial definition of function is shadowed, due to python's binding rules:

The following constructs bind names: formal parameters to functions, import statements, class and function definitions (these bind the class or function name in the defining block)

You can trace it and verify such behaviour using python3 -m trace --trace script.py :

--- modulename: script, funcname: <lambda>
script.py(6):     function = lambda x: function(x) * fun(x)
--- modulename: script, funcname: <lambda>
script.py(6):     function = lambda x: function(x) * fun(x)

# Repeated until a RecursionError is thrown

You can instead bind your function as an argument of the lambda:

fun = lambda x: x**2
function = lambda x: x**2
for i in range(2):
    function = lambda x, y=function: y(x) * fun(x)

print(function(2))

Which will produce the following trace:

--- modulename: script, funcname: <module>
script.py(3): fun = lambda x: x**2
script.py(4): function = lambda x: x**2
script.py(5): for i in range(2):
script.py(6):     function = lambda x, y=function: y(x) * fun(x)
script.py(5): for i in range(2):
script.py(6):     function = lambda x, y=function: y(x) * fun(x)
script.py(5): for i in range(2):
script.py(8): print(function(2))
--- modulename: script, funcname: <lambda>
script.py(6):     function = lambda x, y=function: y(x) * fun(x)
--- modulename: script, funcname: <lambda>
script.py(6):     function = lambda x, y=function: y(x) * fun(x)
--- modulename: script, funcname: <lambda>
script.py(4): function = lambda x: x**2
--- modulename: script, funcname: <lambda>
script.py(3): fun = lambda x: x**2
--- modulename: script, funcname: <lambda>
script.py(3): fun = lambda x: x**2
64

Upvotes: 1

Related Questions