gpt4 book ai didi

Python通过函数装饰器改造ast

转载 作者:太空狗 更新时间:2023-10-30 01:30:45 34 4
gpt4 key购买 nike

我有一个想法来转换使用类似于下面的装饰器标记的所有给定函数,

@transform_ast
def foo(x):
return x

transform_ast 中,我获取源代码、提取 ast、转换它,然后再次从中创建代码对象和函数类型。它看起来像下面,

import ast
import inspect
import types

class Rewrite(ast.NodeTransformer):
pass

def transform_ast(f):

source = inspect.getsource(f)
source = '\n'.join(source.splitlines()[1:]) # remove the decorator first line.
print(source)

old_code_obj = f.__code__
old_ast = ast.parse(source)
new_ast = Rewrite().visit(old_ast)
new_code_obj = compile(new_ast, old_code_obj.co_filename, 'exec')
new_f = types.FunctionType(new_code_obj, {})
return new_f

@transform_ast
def foo(x):
return x

但是,当我随后调用 foo(x) 时,它似乎无法正常工作。

出于所有实际目的,我们可以假设我的转换只是将 return x 重写为 return x+1。理想情况下,我希望一切都能正常工作,包括能够使用调试器进入函数...

调用foo(10),会出现以下错误,

TypeError: module() takes no arguments (1 given)

我做错了什么吗?

最佳答案

new_code_obj = compile(new_ast, old_code_obj.co_filename, 'exec')

使用exec 模式编译的代码总是被视为模块级代码,当然,它可以包含函数或类定义,或任何其他有效的 Python)。

要验证这一点,您可以访问 co_name代码对象的属性以获取定义此代码对象的名称

>>> new_code_obj.co_name
<module>

new_code_obj是一个模块对应的代码对象。但是函数foo对应的代码对象在哪里。我们如何访问它?

可以从co_consts访问代码对象的属性,它是字节码中使用的常量元组

>>> new_code_obj.co_consts
(<code object foo at 0x031C3DE0, file "c:/Users/test.py", line 1>, 'foo', None)
>>> new_code_obj.co_consts[0]
<code object foo at 0x031C3DE0, file "c:/Users/test.py", line 1>

要验证此代码对象来自函数 foo,您可以使用 co_name再次属性。

>>> new_code_obj.co_consts[0].co_name
foo

因此,在创建新的 FunctionType 时,您应该使用与函数 foo 对应的代码对象,而不是 module 代码对象。

变化多端

new_f = types.FunctionType(new_code_obj, {})

new_f = types.FunctionType(new_code_obj.co_consts[0], f.__globals__)
# Here `f` is the function object passed to the `transform_ast`

将解决问题。

附加引用:Exploring Python Code Objects

关于Python通过函数装饰器改造ast,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57480368/

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