Ecir Hana
Ecir Hana

Reputation: 11508

Python: dynamically create function at runtime

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, ...

Upvotes: 83

Views: 105401

Answers (9)

stam
stam

Reputation: 349

for the sake of completeness, the way how dynamically created function works can be simply parametrized

def dynamically_create_greeting(greet_style):
    def inner(name):
        print(f'{greet_style} {name}')

    return inner


say_hello = dynamically_create_greeting(greet_style='hello')
say_hello('John')

say_hi = dynamically_create_greeting(greet_style='hi')
say_hi('John')

this produces output >

hello John

hi John

Upvotes: 1

Rubén Pozo
Rubén Pozo

Reputation: 1083

In my case I need a function returning the function to save it into a variable:

def create_function(function_name, function_arguments, function_code):
    function_string = f"def {function_name}({function_arguments}): {function_code}"
    exec(function_string)
    return_value = eval(function_name)
    return return_value

name = 'say_hello'
arguments = 'name'
code = 'print(f"Hello, {name}!")'

myfunc = create_function(name, arguments, code)

print(myfunc, type(myfunc))
myfunc('John Doe')

Upvotes: 1

milahu
milahu

Reputation: 3609

simpler than Berci's answer

def get_fn(a, b): # factory function
  def fn(): # result function
    print(a, b)
  return fn

fn = get_fn(1, 2)

fn()

this is useful to turn variables into constants ("template variables for dynamic functions")

Upvotes: 1

Helio Junior
Helio Junior

Reputation: 163

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.

Upvotes: 4

vishnu m c
vishnu m c

Reputation: 887

You can use lambda for this.

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

Upvotes: 14

Ahsan
Ahsan

Reputation: 11832

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)

Upvotes: 40

kdw
kdw

Reputation: 449

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.

Upvotes: 34

Berci
Berci

Reputation: 594

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.

Upvotes: 9

mavroprovato
mavroprovato

Reputation: 8372

Use exec:

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

Upvotes: 44

Related Questions