【问题标题】:Python: dynamically create function at runtimePython:在运行时动态创建函数
【发布时间】:2012-07-02 17:22:22
【问题描述】:

如何在 Python 中动态创建函数?

我在这里看到了一些答案,但我找不到能描述最一般情况的答案。

考虑:

def a(x):
    return x + 1

如何即时创建这样的功能?我必须compile('...', 'name', 'exec')吗?但那又如何呢?从编译步骤创建一个虚拟函数并替换其代码对象?

或者我应该使用types.FunctionType?怎么样?

我想自定义所有内容:参数的数量、它们的内容、函数体中的代码、结果……

【问题讨论】:

  • 我不认为它是重复的:dynf = FunctionType(compile('def f(x): return x + 3', 'dyn.py', 'exec'), globals())print dynf(1)TypeError: '<module>() takes no arguments (1 given)' 中断
  • 仅仅因为答案可能错误并不意味着这不是重复的问题。
  • 链接的问题有一个更新的答案,展示了如何创建一个带参数的函数。
  • 您确定无法使用 Python 中存在的函数式编程(lambda、闭包、组合...)实现您想要的吗?代码对象很繁琐,并且没有很好的文档记录(或根本没有记录)。此外,它们被视为内部组件,可能会在通知或不通知的情况下进行更改。

标签: python function runtime


【解决方案1】:

使用exec:

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

【讨论】:

    【解决方案2】:

    你看到this了吗,这是一个告诉你如何使用types.FunctionType的例子

    示例:

    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)
    

    【讨论】:

    • 是的,我看到了,这似乎正是我所追求的。但我不知道如何创建/修改函数体和返回值..?
    • 我刚试了一下,当你用正确的 nb args 更改最后的调用时,它会出现段错误......
    • 你有没有尝试过执行这段代码?因为这段代码无法运行。
    【解决方案3】:

    这种方法怎么样?

    在这个例子中,我在一个类的一个变量 (x -> ax+b) 上参数化一阶函数:

    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
    

    这里u 将是函数x->2x+3。

    【讨论】:

      【解决方案4】:

      如果你需要从某个模板动态创建一个函数,试试这个:

      def create_a_function(*args, **kwargs):
      
          def function_template(*args, **kwargs):
              pass
      
          return function_template
      
      my_new_function = create_a_function()
      

      在函数create_a_function() 中,您可以控制选择哪个模板。内部函数 function_template 用作模板。创建者函数的返回值是一个函数。分配后,您将 my_new_function 用作常规函数。

      通常,此模式用于函数装饰器,但在这里也可以派上用场。

      【讨论】:

      • 谢谢!正是我想要的。我的用例是根据我的动态生成的类属性之一创建一个函数。但它不应该依赖于“自我”。因此它是一个以参数为参数的静态函数create_a_function。因此,该属性可以在内部函数中用作普通变量,并且该函数被分离:-)
      • 有限制,不能被pickle序列化
      【解决方案5】:

      您可以为此使用 lambda。

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

      【讨论】:

      • 这几乎是我现在正在使用的。在我的情况下,我需要将函数动态构建为字符串或预编译配置的字符串表达式,因此我使用了a = eval("lambda x: x + 1"),但结果是一样的。在我的例子中,我还为表达式提供数学函数,所以我还在计算和执行 lambda 的 python 脚本中添加了from math import *
      • 请注意,您可以使用它来创建可以像generic['d'](3) 一样运行的函数列表或字典
      【解决方案6】:

      你可以这样做:

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

      和之前的 exec 方案类似。

      【讨论】:

        【解决方案7】:

        比 Berci 的回答简单

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

        这对于将变量转换为常量很有用(“动态函数的模板变量”)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-03-15
          • 1970-01-01
          • 2021-06-27
          • 2012-06-16
          • 1970-01-01
          • 2020-05-04
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多