我有一个名为example_dict.py的文件
#This is a valid comment
{
'key1': 'value1',
'key2': 'value2',
'key3': 'value3',
}
Run Code Online (Sandbox Code Playgroud)
然后我读了这个文件并转换dict:
from collections import OrderedDict
with open("example_dict.py") as fp:
dict_from_file = OrderedDict( eval( fp.read() ) )
Run Code Online (Sandbox Code Playgroud)
但是这个"dict_from_file"没有相同的顺序key1,key2,key3.
我怎么能以同样的顺序得到这个字典.
您可以使用该ast模块编写自定义解析器,作为启动器:
import ast
from collections import OrderedDict
with open('example_dict.py') as fin:
parsed = ast.parse(fin.read())
first_dict = next(node for node in ast.walk(parsed) if isinstance(node, ast.Dict))
keys = (node.s for node in first_dict.keys)
vals = (node.s for node in first_dict.values)
od = OrderedDict(zip(keys, vals))
# OrderedDict([('key1', 'value1'), ('key2', 'value2'), ('key3', 'value3')])
Run Code Online (Sandbox Code Playgroud)
请注意,尽管这适用于您的示例数据 - 这需要更多的工作才能使其更加健壮,但应该作为起点.
@JonClements的解决方案既美观又简单 - 但是,正如他所指出的那样,它并不那么健壮,因为你依赖于字典显示的每个元素都会评估自己的事实 - 并且你有一些任意的代码其中第一个有效的dict文字是你唯一关心的事情.
一个相关的想法是使用ast.NodeTransformer将dict文字AST转换为OrderedDict构造函数AST,然后就是eval这样.
优点:
缺点:
literal_eval在每个元素上使用).但是,值得回过头来询问您是否真的想要编写并使用所有这些代码.你可能会使用类似开心了很多MacroPy,它能够自动了很多笨重的东西在这里正在做的,和很多我的东西不是在这里做什么(如安装进口钩),让你集中精力的只是一部分你感兴趣的转变.(实际上,我认为MacroPy甚至带有一个odict文字作为其内置示例之一...)
无论如何,变压器看起来像这样:
class DictToOrdered(ast.NodeTransformer):
def visit_Dict(self, node):
return ast.fix_missing_locations(ast.copy_location(
ast.Call(
func=ast.Attribute(
value=ast.Name(id='collections', ctx=ast.Load()),
attr='OrderedDict',
ctx=ast.Load()),
args=[ast.Tuple(elts=
[ast.Tuple(elts=list(pair), ctx=ast.Load())
for pair in zip(node.keys, node.values)],
ctx=ast.Load())],
keywords=[],
starargs=None,
kwargs=None),
node))
Run Code Online (Sandbox Code Playgroud)
这比平时稍微丑陋,因为dict文字不必有上下文(因为它们不能用作赋值目标),但是元组做(因为它们可以),所以我们不能只复制上下文我们做行号的方式.
要使用它:
def parse_dict_as_odict(src):
import collections
parsed = ast.parse(src, '<dynamic>', 'eval')
transformed = DictToOrdered().visit(parsed)
compiled = compile(transformed, '<dynamic>', 'eval')
return eval(compiled)
Run Code Online (Sandbox Code Playgroud)
这假设您希望一次只评估一个表达式,并且您希望在当前的全局/本地环境中这样做,并且您不介意将collections模块插入该环境中; 如果你看一下文档的compile,ast.parse和eval它应该是明显如何更改其中的任何假设.
所以:
>>> src = '''
... {
... 'key1': 'value1',
... 'key2': 'value2',
... 'key3': 'value3',
... }
... '''
>>> parse_dict_as_odict(src)
OrderedDict([('key1', 'value1'), ('key2', 'value2'), ('key3', 'value3')])
Run Code Online (Sandbox Code Playgroud)
如果你想了解更多信息,而不是自己深入研究源代码,那么Green Tree Snakes是理解Python的AST及其ast模块的一个很好的资源,我希望它是几年前编写的.:)
| 归档时间: |
|
| 查看次数: |
573 次 |
| 最近记录: |