我一直在尝试将字典转储到YAML文件中。问题是导入YAML文件的程序需要按特定顺序的关键字。此订单按字母顺序不。
SELECT REPLACE(column_name, ' ', '') FROM table_name
这会生成一个* .yml文件,其格式如下:
import yaml
import os
baseFile = 'myfile.dat'
lyml = [{'BaseFile': baseFile}]
lyml.append({'Environment':{'WaterDepth':0.,'WaveDirection':0.,'WaveGamma':0.,'WaveAlpha':0.}})
CaseName = 'OrderedDict.yml'
CaseDir = r'C:\Users\BTO\Documents\Projects\Mooring code testen'
CaseFile = os.path.join(CaseDir, CaseName)
with open(CaseFile, 'w') as f:
yaml.dump(lyml, f, default_flow_style=False)
但我想要的是保留订单:
- BaseFile: myfile.dat
- Environment:
WaterDepth: 0.0
WaveAlpha: 0.0
WaveDirection: 0.0
WaveGamma: 0.0
这可能吗?
答案 0 :(得分:26)
使用OrderedDict代替dict。在开始时运行以下设置代码。现在yaml.dump
,应保留订单。更多详情here和here
def setup_yaml():
""" https://stackoverflow.com/a/8661021 """
represent_dict_order = lambda self, data: self.represent_mapping('tag:yaml.org,2002:map', data.items())
yaml.add_representer(OrderedDict, represent_dict_order)
setup_yaml()
答案 1 :(得分:4)
PyYAML支持representer
将类实例序列化为YAML节点。
yaml.YAMLObject使用元类魔法来注册构造函数,该构造函数将YAML节点转换为类实例,以及将类实例序列化为YAML节点的表示器。
在代码上方添加以下行:
def represent_dictionary_order(self, dict_data):
return self.represent_mapping('tag:yaml.org,2002:map', dict_data.items())
def setup_yaml():
yaml.add_representer(OrderedDict, represent_dictionary_order)
setup_yaml()
然后,您可以使用OrderedDict
保留yaml.dump()
中的订单:
import yaml
from collections import OrderedDict
def represent_dictionary_order(self, dict_data):
return self.represent_mapping('tag:yaml.org,2002:map', dict_data.items())
def setup_yaml():
yaml.add_representer(OrderedDict, represent_dictionary_order)
setup_yaml()
dic = OrderedDict()
dic['a'] = 1
dic['b'] = 2
dic['c'] = 3
print(yaml.dump(dic))
# {a: 1, b: 2, c: 3}
答案 2 :(得分:1)
您的困难是由于多个级别的假设不正确而导致的,并且取决于您的YAML解析器,可能无法透明地解析。
在Python的dict
中,密钥是无序的(至少对于Python< 3.6)。即使密钥在源文件中有一些顺序,只要它们位于dict
中,它们就不是:
d = {'WaterDepth':0.,'WaveDirection':0.,'WaveGamma':0.,'WaveAlpha':0.}
for key in d:
print key
给出:
WaterDepth
WaveGamma
WaveAlpha
WaveDirection
如果你想要你的密钥订购你可以使用collections.OrderedDict类型(或我自己的ruamel.ordereddict类型,它在C中,并且速度超过一个数量级),你必须添加有序的键,作为元组列表:
from ruamel.ordereddict import ordereddict
# from collections import OrderedDict as ordereddict # < this will work as well
d = ordereddict([('WaterDepth', 0.), ('WaveDirection', 0.), ('WaveGamma', 0.), ('WaveAlpha', 0.)])
for key in d:
print key
将按照在源中指定的顺序打印键。
第二个问题是,即使Python dict有一些恰好是你想要的密钥排序,YAML规范明确地说明映射是无序的,这就是例如PyYAML实现了将Python dict转储到YAML映射(反之亦然)。 此外,如果您转储ordereddict或OrderedDict,通常不会获得您指定所需的普通YAML映射,但会获得一些标记为YAML的条目。
由于丢失订单通常是不可取的,因为您的读者会假定某些订单,在我的情况下因为这使得比较版本很困难,因为插入/删除后密钥排序不一致,我实现了往返一致性在ruamel.yaml中,您可以这样做:
import sys
import ruamel.yaml as yaml
yaml_str = """\
- BaseFile: myfile.dat
- Environment:
WaterDepth: 0.0
WaveDirection: 0.0
WaveGamma: 0.0
WaveAlpha: 0.0
"""
data = yaml.load(yaml_str, Loader=yaml.RoundTripLoader)
print(data)
yaml.dump(data, sys.stdout, Dumper=yaml.RoundTripDumper)
它可以准确地为您提供输出结果。 data
作为dict工作(`data ['Environment']也是如此,但在它们下面是更智能的构造,保留了顺序,注释,YAML锚名称等)。您当然可以更改这些(添加/删除键值对),这很容易,但您也可以从头开始构建这些:
import sys
import ruamel.yaml as yaml
from ruamel.yaml.comments import CommentedMap
baseFile = 'myfile.dat'
lyml = [{'BaseFile': baseFile}]
lyml.append({'Environment': CommentedMap([('WaterDepth', 0.), ('WaveDirection', 0.), ('WaveGamma', 0.), ('WaveAlpha', 0.)])})
yaml.dump(data, sys.stdout, Dumper=yaml.RoundTripDumper)
再次按照您想要的顺序打印内容。 我发现后者比从YAML字符串开始时更不易读,但它确实构建了lyml数据结构的速度更快。
答案 3 :(得分:0)
3年后-yaml.dump的sort_keys kwarg默认设置为True。将其设置为False即可不重新排序:
with open(CaseFile, 'w') as f:
yaml.dump(lyml, f, default_flow_style=False, sort_keys=False)