我有一个包含Python代码的字符串,如果只将OrderedDict
的实例替换为{}
,我可以用literal_eval
将其计算为Python。
我尝试使用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)
发布于 2018-07-10 06:09:58
您可以使用ast.NodeVisitor
类观察OrderedDict
树,以便使用从空字典解析的节点作为基础,从遇到的节点手动构建{}
树。
import ast
from collections import deque
class Builder(ast.NodeVisitor):
def __init__(self):
super().__init__()
self._tree = ast.parse('[{}]')
self._list_node = self._tree.body[0].value
self._dict_node = self._list_node.elts[0]
self._new_item = False
def visit_Tuple(self, node):
self._new_item = True
self.generic_visit(node)
def visit_Str(self, node):
if self._new_item:
self._dict_node.keys.append(node)
self.generic_visit(node)
def visit_Num(self, node):
if self._new_item:
self._dict_node.values.append(node)
self._new_item = False
self.generic_visit(node)
def literal_eval(self):
return ast.literal_eval(self._list_node)
builder = Builder()
builder.visit(ast.parse("[OrderedDict([('a', 1)])]"))
print(builder.literal_eval())
注意,这只适用于使用str
作为键和int
作为值的示例的简单结构。但是,应该可以以类似的方式扩展到更复杂的结构。
发布于 2018-07-10 17:38:18
除了使用ast
解析和转换表达式之外,您还可以使用正则表达式进行解析和转换。例如:
>>> re.sub(
... r"OrderedDict\(\[((\(('[a-z]+'), (\d+)\)),?\s*)+\]\)",
... r'{\3: \4}',
... "[OrderedDict([('a', 1)])]"
... )
"[{'a': 1}]"
上面的表达式基于OP的示例字符串,并将单引号字符串作为键,正整数作为值,当然,它可以扩展到更复杂的情况。
https://stackoverflow.com/questions/51253056
复制相似问题