假设我们有一个这样的代码对象:
code = '''
x = 'unrelated'
y = dangerous_function()
def foo():
return 'say foo'
'''
code_obj = compile(code, '<string>', 'exec')
我不想仅仅执行它,因为谁知道会发生什么(特别是dangerous_function
调用看起来很杂乱)。但是,我愿意用其中定义的任何函数填充当前作用域,这似乎可以做到:
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"
我希望最后一条语句打印say foo
而不是引发NameError
。这样做的原因必须是exec(obj)
并没有执行我期望的操作,即它没有运行在父代码对象中分配给名称foo
的代码对象。 / p>
有办法吗?
答案 0 :(得分:1)
co_const
属性仅包含在代码对象中定义的常量文字,因此在您的示例中,该属性仅包含加载'say foo'
作为返回参数的代码,可以使用{{ 1}}:
dis
这将输出:
import dis
for obj in code_obj.co_consts:
if isinstance(obj, types.CodeType):
dis.dis(obj)
因此,通过执行此代码对象,自然不会定义任何名称。
如果您只想在给定的源代码中执行特定功能,则可以使用 5 0 LOAD_CONST 1 ('say foo')
2 RETURN_VALUE
解析代码,并使用ast.parse
子类提取功能节点,并用{包裹{1}}节点,因此您可以单独编译和执行它:
ast.NodeVisitor
这将输出:
Module
编辑:或者更简单地,您可以使用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'))
函数通过<function foo at 0x018735D0>
循环遍历节点:
ast.walk