How to execute nested PyCode objects
假设我们有这样的代码对象:
1 2 3 4 5 6 7 8 | code = ''' x = 'unrelated' y = dangerous_function() def foo(): return 'say foo' ''' code_obj = compile(code, '<string>', 'exec') |
我不想只执行它,因为谁知道会发生什么(特别是
1 2 3 4 5 6 7 8 9 10 11 12 | import types new_objects = [] for obj in code_obj.co_consts: if isinstance(obj, types.CodeType): new_objects.append(obj.co_name) print(obj) #"<code object foo at 0x7f4e255d3150, file"<string>", line 4>" # ... looks promising, so let's exec it! exec(obj) print(new_objects[0]) #"foo" print(eval(new_objects[0])) #"NameError: name 'foo' is not defined" |
我本以为最后一份声明是打印
有办法吗?
1 2 3 4 | import dis for obj in code_obj.co_consts: if isinstance(obj, types.CodeType): dis.dis(obj) |
此输出:
1 2 | 5 0 LOAD_CONST 1 ('say foo') 2 RETURN_VALUE |
因此,通过执行这个代码对象,它自然不会定义任何名称。
如果您只想在给定的源代码中执行一个特定的函数,您可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import ast class get_function(ast.NodeVisitor): def __init__(self, name): self.name = name self.code = None def visit_FunctionDef(self, node): if node.name == self.name: self.code = compile(ast.fix_missing_locations(ast.Module(body=[node])), '<string>', 'exec') func = get_function('foo') func.visit(ast.parse(code, '<string>')) exec(func.code) print(eval('foo')) |
此输出:
1 | <function foo at 0x018735D0> |
编辑:或者更简单地说,您可以使用
1 2 3 4 5 6 7 8 | import ast for node in ast.walk(ast.parse(code, '<string>')): if isinstance(node, ast.FunctionDef) and node.name == 'foo': code_obj = compile(ast.fix_missing_locations(ast.Module(body=[node])), '<string>', 'exec') exec(code_obj) print(eval('foo')) |