There are a number of ways to do this kind of thing.
If the function can be described without "stepping outside the language", you can just define a local function and return it, as in Blender's answer. This is usually what you want when you think you need to define new functions (borrowing Blender's example):
def make_func(a, b):
def f(n):
return n**a + b
return f
Sometimes, you can do even better, and represent the functions as data. For example, how do you create an arbitrary polynomial function? Well, you don't have to; you can have a generic polynomial function that takes a list of coefficients and a value and evaluates it; then all you need to do is create coefficient lists.
In fact, I think this is the one you want here. As you say:
It may be return 2*f(n-1) - 4*f(n-2) - 5*f(n-3) + 15*f(n-4) one minute, or return f(n-1) + 3*f(n-2) another, or f(n-1)+f(n-2)+f(n-3)+f(n-4)+5*f(n-5) depending on what I need it to be.
This can definitely be represented as a list of coefficients:
def make_recursive_func(coefficients, baseval):
def f(n):
if n < len(coefficients): return baseval[n]
return sum(coefficient * f(n-i-1) for i, coefficient in enumerate(coefficients))
return f
But it's probably even simpler to write a single eval_recursive_func(coefficients, baseval)
, if all you're ever going to do with the returned function is call it immediately and then forget it.
Sometimes—rarely, but not never—you really do need to execute code on the fly. As Himanshu says, eval
and exec
and friends are the way to do this. For example:
newcode = '''
def f(n):
if n<=3: return [0, 0, 6, 12][n]
return 2*f(n-1) - 4*f(n-2) - 5*f(n-3) + 15*f(n-4)
'''
exec(newcode)
Now the f
function has been defined, exactly as if you'd just done this:
def f(n):
if n<=3: return [0, 0, 6, 12][n]
return 2*f(n-1) - 4*f(n-2) - 5*f(n-3) + 15*f(n-4)
It's a bit different in Py3 than Py2, and there are variations depending on what context you want things executed in, or whether you just want it executed or evaluated or compiled or treated like an import, etc. But this is the basic idea.
If you can't think of why you'd want to write the first instead of the second, then you don't need this.
And if you can't figure out how to generate the right string on the fly, you shouldn't be doing this.
And, as Ignacio Vazquez-Abrams points out, if these functions can be built out of user input, you need to do something to validate that they're safe, usually by compiling iteratively and walking the AST.
Finally, even more rarely, you need to use the new
module (and/or inspect
) to create a new function object on the fly out of bits of other function objects (or even out of hand-crafted bytecode). But if you need to know how to do that, you probably already know how.