跳转到主要内容

Python AST工作工具箱

项目描述

Build Status Coverage Status

Python AST工作工具箱

pip install ast_tools

有用参考资料

Passes

ast_tools提供了一系列用于重写函数和类的passes(也可以在模块级别工作,但不存在此类pass)。通过apply_passes装饰器应用passes。

@apply_passes([pass1(), pass2()])
def foo(...): ...

每个pass将AST、环境和元数据作为参数,并返回(可能)修改后的版本。apply_passes通过首先查找装饰对象的ast,并尝试从调用站点收集局部和全局变量来构建环境,开始一系列重写。

所有重写运行完毕后,apply_passes将序列化和执行重写的ast。

已知问题

收集AST

apply_passes依赖于inspect.getsource来获取装饰定义的源代码(然后解析以获取初始ast)。然而,inspect.getsource有很多限制。

收集环境

apply_passes尽力推断环境,但无法完全正确地执行此操作。鼓励用户明确传递环境。

@apply_passes(..., env=SymbolTable(locals(), globals()))
def foo(...): ...

包装apply_passes装饰器

apply_passes装饰器不能被包装。

作为装饰器是它们应用到的对象的AST的一部分,它们必须在执行之前从重写的AST中移除。如果没有移除,重写将无限递归,因为

@apply_passes([...])
def foo(...): ...

将变成

exec('''\
@apply_passes([...])
def rewritten_foo(...): ...
''')

注意:这将调用apply_passes([...])rewritten_foo

为了避免这种情况,apply_passes装饰器从装饰器列表中过滤掉自己。然而,如果装饰器包装在另一个装饰器内部,这将失败。

内部装饰器被多次调用

在重写组之前应用装饰器将多次调用。请参阅https://github.com/leonardt/ast_tools/issues/46以获取详细解释。为了避免这种情况,鼓励用户尽可能将重写放在最内层的装饰器中。

循环展开

使用以下模式展开循环

for <var> in ast_tools.macros.unroll(<iter>):
    ...

<iter> 应该是一个可迭代对象,它生成整数(例如 range(8)),在定义时可以评估(可以在函数定义的作用域中引用变量)。

例如,

from ast_tools.passes import apply_passes, loop_unroll

@apply_passes([loop_unroll()])
def foo():
    for i in ast_tools.macros.unroll(range(8)):
        print(i)

会被重写为

def foo():
    print(0)
    print(1)
    print(2)
    print(3)
    print(4)
    print(5)
    print(6)
    print(7)

您还可以使用整数的列表,这里有一个也使用外部作用域中定义的变量引用的例子。

from ast_tools.passes import apply_passes, loop_unroll

j = [1, 2, 3]
@apply_passes([loop_unroll()])
def foo():
    for i in ast_tools.macros.unroll(j):
        print(i)

变为

def foo():
    print(1)
    print(2)
    print(3)

内联 If 语句

此宏允许您在函数定义时评估 if 语句,因此重写后的函数将移除标记为“内联”的 if 语句,并根据在定义的封装作用域中评估的条件替换为选择的分支。if 语句通过使用形式 if inline(...): 进行标记,其中 inlineast_tools.macros 包中导入。if 语句不匹配此模式将被重写逻辑忽略。

以下是一个示例

from ast_tools.macros import inline
from ast_tools.passes import apply_passes, if_inline

y = True

@apply_passes([if_inline()])
def foo(x):
    if inline(y):
        return x + 1
    else:
        return x - 1


import inspect
assert inspect.getsource(foo) == f"""\
def foo(x):
    return x + 1
"""

项目详情


下载文件

下载您平台的文件。如果您不确定选择哪一个,请了解更多关于 安装包 的信息。

源分布

此版本没有可用的源分布文件。请参阅 生成分布存档 的教程。

构建分布

ast_tools-0.1.8-py38-none-any.whl (43.6 kB 查看散列值)

上传时间 Python 3.8

ast_tools-0.1.8-py37-none-any.whl (43.4 kB 查看散列值)

上传时间 Python 3.7

ast_tools-0.1.8-py3-none-any.whl (43.6 kB 查看散列值)

上传时间 Python 3

支持者

AWSAWS云计算和安全赞助商DatadogDatadog监控FastlyFastlyCDNGoogleGoogle下载分析MicrosoftMicrosoftPSF赞助商PingdomPingdom监控SentrySentry错误日志StatusPageStatusPage状态页面