59
votes

How to dynamically create a function in Python?

I saw a few answers here but I couldn't find one which would describe the most general case.

Consider:

def a(x):
    return x + 1

How to create such function on-the-fly? Do I have to compile('...', 'name', 'exec') it? But what then? Creating a dummy function and replacing its code object for then one from the compile step?

Or should I use types.FunctionType? How?

I would like to customize everything: number of argument, their content, code in function body, the result, ...

6
I don't think it a duplicate: dynf = FunctionType(compile('def f(x): return x + 3', 'dyn.py', 'exec'), globals()) and print dynf(1) breaks with TypeError: '<module>() takes no arguments (1 given)' - Ecir Hana
Just because the answer there might be wrong doesn't mean this isn't a duplicate question. - Martijn Pieters♦
The linked question has an updated answer demonstrating how to create a function with arguments. - Martijn Pieters♦
are you sure you can't achieve what you want using functional programming as it exists in python (lambdas, closures, compositions...)? the code objects are fiddly, and they're not well documented (or really at all). Plus they're considered internals, subject to change with or without notice. - Xingzhou Liu

6 Answers

36
votes

Use exec:

>>> exec("""def a(x):
...   return x+1""")
>>> a(2)
3
27
votes

Did you see this, its an example which tells you how to use types.FunctionType

Example:

import types

def create_function(name, args):
    def y(): pass

    y_code = types.CodeType(args,
                            y.func_code.co_nlocals,
                            y.func_code.co_stacksize,
                            y.func_code.co_flags,
                            y.func_code.co_code,
                            y.func_code.co_consts,
                            y.func_code.co_names,
                            y.func_code.co_varnames,
                            y.func_code.co_filename,
                            name,
                            y.func_code.co_firstlineno,
                            y.func_code.co_lnotab)

    return types.FunctionType(y_code, y.func_globals, name)

myfunc = create_function('myfunc', 3)

print repr(myfunc)
print myfunc.func_name
print myfunc.func_code.co_argcount

myfunc(1,2,3,4)
# TypeError: myfunc() takes exactly 3 arguments (4 given)
18
votes

If you need to dynamically create a function from a certain template try this piece:

def create_a_function(*args, **kwargs):

    def function_template(*args, **kwargs):
        pass

    return function_template

my_new_function = create_a_function()

Within function create_a_function() you can control, which template to chose. The inner function function_template serves as template. The return value of the creator function is a function. After assignment you use my_new_function as a regular function.

Typically, this pattern is used for function decorators, but might by handy here, too.

11
votes

You can use lambda for this.

a = lambda x: x + 1
>>> a(2)
3
4
votes

You can do at this manner:

new_func='def next_element(x):\n  return x+1'
the_code=compile(new_func,'test','exec')
exec(the_code)
next_element(1)

It's similar to the previous exec solution.

3
votes

What about this approach?

In this example I'm parametrizing first order functions on one variable (x -> ax+b) in one class:

class Fun: 
  def __init__(self, a,b):
    self.a, self.b = a,b

  def f(self, x):
    return (x*self.a + self.b)

 u = Fun(2,3).f

Here u will be the function x->2x+3.