您可以递归遍历 AST
,当在赋值语句中遇到列表推导式 (ast.ListComp
) 时,您可以删除父级赋值对象并将从推导式派生的标准 for 循环插入到主体作用域中:
import ast
def comp_to_expl(tree):
if hasattr(tree, 'body'):
i = 0
while i < len(tree.body):
if isinstance(a:=tree.body[i], ast.Assign) and isinstance(a.value, ast.ListComp):
tree.body = tree.body[:i] + \
[ast.Assign(
targets=[ast.Name(id = a.targets[0].id)], value = ast.List(elts = []),
lineno = a.lineno
)] + \
[ast.For(
target = a.value.generators[0].target,
iter = a.value.generators[0].iter,
body = [ast.Expr(
value = ast.Call(
func = ast.Attribute(value = ast.Name(id = a.targets[0].id), attr = 'append', ctx = ast.Load()),
args = [a.value.elt],
keywords = []
))],
lineno = a.lineno+1,
orelse = [],
)] + \
tree.body[i+1:]
i += 1
i += 1
for i in getattr(tree, '_fields', []):
if isinstance(v:=getattr(tree, i, None), list):
for i in v:
comp_to_expl(i)
elif isinstance(v, ast.AST):
comp_to_expl(v)
synt = ast.parse('a=[x for x in [1,2,3]]')
comp_to_expl(synt)
print(ast.unparse(synt))
输出:
a = []
for x in [1, 2, 3]:
a.append(x)
foo(x+2 for x in arr)
。实际上,对于[expr for variable in generator]
的等效操作是使用内置的列表构造函数:list(expr for variable in generator)
。 (如果expr
只是变量x for x in...
,则可以将其丢弃:list(generator)
。不过我不知道这是否真正对您有所帮助 :-( - rici