如何在模块中动态创建 python 函数?

How to dynamically create a python function within a module?

我写了一个函数 def_function,它在运行时动态定义了另一个函数。

main.py

#!/usr/bin/python3

def def_function(name):
  lines = list()
  lines.append('global {}\n'.format(name))
  lines.append('def {}():\n'.format(name))
  lines.append('  print(\'{}() has been called!\')\n'.format(name))
  code = ''.join(lines)
  function = compile(code, '', 'exec')
  exec(function)

def_function('foo')
foo()

运行 main.py 给出了预期的输出:

foo() has been called!

现在我想将 def_function 的定义移动到 module.py 并从 main.py 导入它。

module.py

def def_function(name):
  lines = list()
  lines.append('global {}\n'.format(name))
  lines.append('def {}():\n'.format(name))
  lines.append('  print(\'{}() has been called!\')\n'.format(name))
  code = ''.join(lines)
  function = compile(code, '', 'exec')
  exec(function)

main.py

#!/usr/bin/python3

from module import def_function

def_function('foo')
foo()

这会导致以下错误:

Traceback (most recent call last):
  File "./main.py", line 6, in <module>
    foo()
NameError: name 'foo' is not defined

我已经用谷歌搜索了我的问题并阅读了 SO 上的各种问题,但找不到解决方案。请帮助我。

您在 module.py 范围内定义 foo。不要忘记导入 module.py.

调用 foo(),作为 module.foo()

import module

module.def_function('foo')
module.foo()

可能对你有帮助https://realpython.com/python-scope-legb-rule/

额外

exec(function) 之后添加这个。同时导入 sys.

setattr(sys.modules['__main__'], name, globals()[name])

Setattr 它的功能是将值分配给对象的属性或创建新的属性。 https://docs.python.org/3/library/functions.html#setattr

module.py

import sys


def def_function(name):
    lines = list()
    lines.append('global {}\n'.format(name))
    lines.append('def {}():\n'.format(name))
    lines.append('  print(\'{}() has been called!\')\n'.format(name))
    code = ''.join(lines)
    function = compile(code, '', 'exec')
    exec(function)
    setattr(sys.modules['__main__'], name, globals()[name])

main.py

from module import def_function

def_function('foo')
foo()

你的例子可以这样写,有一个嵌套的函数定义,没有compileexec:

def def_function(name):
    def f():
        print(name, "has been called")
    return f

# ...

foo = def_function("foo")

但是,您必须 return 它。