Как я могу динамически выполнять функцию в текущей области и добавлять ее как свойство вызывающей функции?
У меня есть код такой:
def f1(): <some stuff here> . . . @mylib.codegen def f2(args): f1() <some more stuff here>
mylib.py:
def codegen(fn): src = inspect.getsource(fn) original_ast = ast.parse(src) new_ast = transform_ast(original_ast) code_obj = compile(new_ast, '<auto-generated>', 'exec') myscope = {} exec code_obj in myscope fn.generated_fn = myscope['name'] # Where name is the binding created by execing code_obj
Подводя итог, mylib.codegen
– это декоратор, который разбирает код f, создает аспект другой функции, основанной на f
, execs кода сгенерированной функции для получения вызываемой функции и устанавливает вызываемую функцию как свойство f
. Это означает, что когда f2
импортируется в первый раз, f2
динамически получает другую функцию как свойство самого себя.
Сгенерированная функция также должна вызывать f1
но она не может найти f1
в myscope
. Если бы какой-то Python разрешил встраивание, и у меня был встроенный код mylib.codegen
, все было бы хорошо, но я не думаю, что Python позволяет встраивать код. Как я устанавливаю вещи так, чтобы сгенерированный объект кода выполнялся в пространстве имен функции вызывающего абонента?
fn.func_globals
содержит глобальное пространство имен для данной функции; вам понадобится это, чтобы иметь возможность выполнить преобразованный и перекомпилированный объект кода:
myscope = {} myscope.update(fn.func_globals)
Не используйте fn.func_globals
напрямую; вы не захотите переписывать элементы в этом пространстве имен.