gpt4 book ai didi

python - 如何执行嵌套的 PyCode 对象

转载 作者:太空宇宙 更新时间:2023-11-04 04:17:27 24 4
gpt4 key购买 nike

假设我们有这样一个代码对象:

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 的代码对象在父代码对象中。

有办法吗?

最佳答案

co_const 属性仅包含代码对象中定义的常量文字,因此在您的示例中,它仅包含加载 'say foo' 作为参数的代码返回,可以用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 解析代码并使用 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 函数通过 for 循环遍历节点:

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'))

关于python - 如何执行嵌套的 PyCode 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55162664/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com