Jim*_*ker 6 python abstract-syntax-tree
我有一个包含Python代码的字符串,我可以将其评估为Python,literal_eval如果它只有OrderedDict替换的实例{}.
我正在尝试使用ast.parse和ast.NodeTransformer进行替换,但是当我捕获节点时nodetype == 'Name' and node.id == 'OrderedDict',我找不到节点对象中的参数列表,以便我可以用Dict节点替换它.
这甚至是正确的方法吗?
一些代码:
from ast import NodeTransformer, parse
py_str = "[OrderedDict([('a', 1)])]"
class Transformer(NodeTransformer):
def generic_visit(self, node):
nodetype = type(node).__name__
if nodetype == 'Name' and node.id == 'OrderedDict':
pass # ???
return NodeTransformer.generic_visit(self, node)
t = Transformer()
tree = parse(py_str)
t.visit(tree)
Run Code Online (Sandbox Code Playgroud)
这个想法是将所有OrderedDict表示为ast.Call具有特定属性的节点(可以从下面看到ordered_dict_conditions)替换为从参数中提取/参数的ast.Dict节点。keyvalueast.Call
import ast
class Transformer(ast.NodeTransformer):
def generic_visit(self, node):
# Need to call super() in any case to visit child nodes of the current one.
super().generic_visit(node)
ordered_dict_conditions = (
isinstance(node, ast.Call)
and isinstance(node.func, ast.Name)
and node.func.id == 'OrderedDict'
and len(node.args) == 1
and isinstance(node.args[0], ast.List)
)
if ordered_dict_conditions:
return ast.Dict(
[x.elts[0] for x in node.args[0].elts],
[x.elts[1] for x in node.args[0].elts]
)
return node
def transform_eval(py_str):
return ast.literal_eval(Transformer().visit(ast.parse(py_str, mode='eval')).body)
print(transform_eval("[OrderedDict([('a', 1)]), {'k': 'v'}]")) # [{'a': 1}, {'k': 'v'}]
print(transform_eval("OrderedDict([('a', OrderedDict([('b', 1)]))])")) # {'a': {'b': 1}}
Run Code Online (Sandbox Code Playgroud)
因为我们想首先替换最里面的节点,所以我们super()在函数的开头调用 。
每当OrderedDict遇到节点时,都会使用以下内容:
node.args是一个包含调用参数的列表OrderedDict(...)。node.args[0]( ast.List) 访问,并且node.args[0].elts是包装在list.node.args[0].elts[i]不同的ast.Tuples ( ) 的元素也for i in range(len(node.args[0].elts))可以通过属性再次访问.elts。node.args[0].elts[i].elts[0]是调用中使用的键和node.args[0].elts[i].elts[1]值OrderedDict。然后,后面的键和值用于创建一个新ast.Dict实例,然后用该实例替换当前节点(原为ast.Call)。
| 归档时间: |
|
| 查看次数: |
238 次 |
| 最近记录: |