mwc*_*wcz 36 python dictionary yaml pyyaml
我正在使用yaml.dump输出字典.它根据键按字母顺序打印出每个项目.
>>> d = {"z":0,"y":0,"x":0}
>>> yaml.dump( d, default_flow_style=False )
'x: 0\ny: 0\nz: 0\n'
Run Code Online (Sandbox Code Playgroud)
有没有办法控制键/值对的顺序?
在我的特定用例中,反向打印(巧合)就足够了.但是为了完整性,我正在寻找一个答案,展示如何更精确地控制订单.
我看过使用collections.OrderedDict但是PyYAML没有(似乎)支持它.我也看过子类化yaml.Dumper,但我无法弄清楚它是否有能力改变项目顺序.
Coo*_*.Wu 47
如果您现在将PyYAML升级到5.1版本,它将支持转储而不对键进行排序,如下所示:
yaml.dump(data, default_flow_style=False, sort_keys=False)
Run Code Online (Sandbox Code Playgroud)
这是很新的东西,只是在几个小时前我输入时才修复的。
Ble*_*der 41
可能有更好的解决方法,但我在文档或源代码中找不到任何内容.
Python 2(见评论)
我将其子类化OrderedDict并返回一个不可解决的项目列表:
from collections import OrderedDict
class UnsortableList(list):
def sort(self, *args, **kwargs):
pass
class UnsortableOrderedDict(OrderedDict):
def items(self, *args, **kwargs):
return UnsortableList(OrderedDict.items(self, *args, **kwargs))
yaml.add_representer(UnsortableOrderedDict, yaml.representer.SafeRepresenter.represent_dict)
Run Code Online (Sandbox Code Playgroud)
它似乎工作:
>>> d = UnsortableOrderedDict([
... ('z', 0),
... ('y', 0),
... ('x', 0)
... ])
>>> yaml.dump(d, default_flow_style=False)
'z: 0\ny: 0\nx: 0\n'
Run Code Online (Sandbox Code Playgroud)
Python 3或2(见评论)
您也可以编写自定义代表,但我不知道您以后是否会遇到问题,因为我从中删除了一些样式检查代码:
import yaml
from collections import OrderedDict
def represent_ordereddict(dumper, data):
value = []
for item_key, item_value in data.items():
node_key = dumper.represent_data(item_key)
node_value = dumper.represent_data(item_value)
value.append((node_key, node_value))
return yaml.nodes.MappingNode(u'tag:yaml.org,2002:map', value)
yaml.add_representer(OrderedDict, represent_ordereddict)
Run Code Online (Sandbox Code Playgroud)
但有了这个,你可以使用本机OrderedDict类.
wim*_*wim 12
对于 Python 3.7+,dicts 保留插入顺序。从 PyYAML 5.1.x 开始,您可以禁用键的排序 ( #254 )。不幸的是,排序键行为仍然默认为True。
>>> import yaml
>>> yaml.dump({"b":1, "a": 2})
'a: 2\nb: 1\n'
>>> yaml.dump({"b":1, "a": 2}, sort_keys=False)
'b: 1\na: 2\n'
Run Code Online (Sandbox Code Playgroud)
我的项目oyaml是 PyYAML 的monkeypatch/drop-in 替代品。默认情况下,它将在所有 Python 版本和 PyYAML 版本中保留 dict 顺序。
>>> import oyaml as yaml # pip install oyaml
>>> yaml.dump({"b":1, "a": 2})
'b: 1\na: 2\n'
Run Code Online (Sandbox Code Playgroud)
此外,它会将collections.OrderedDict子类转储为普通映射,而不是 Python 对象。
>>> from collections import OrderedDict
>>> d = OrderedDict([("b", 1), ("a", 2)])
>>> import yaml
>>> yaml.dump(d)
'!!python/object/apply:collections.OrderedDict\n- - - b\n - 1\n - - a\n - 2\n'
>>> yaml.safe_dump(d)
RepresenterError: ('cannot represent an object', OrderedDict([('b', 1), ('a', 2)]))
>>> import oyaml as yaml
>>> yaml.dump(d)
'b: 1\na: 2\n'
>>> yaml.safe_dump(d)
'b: 1\na: 2\n'
Run Code Online (Sandbox Code Playgroud)
Ark*_*kun 11
单行来统治它们:
yaml.add_representer(dict, lambda self, data: yaml.representer.SafeRepresenter.represent_dict(self, data.items()))
Run Code Online (Sandbox Code Playgroud)
而已.最后.经过represent_dict这么多年和数小时之后,强大的力量已被击败dict.items()而不仅仅是让它失败了dict
下面是它的工作原理:
这是相关的PyYaml源代码:
if hasattr(mapping, 'items'):
mapping = list(mapping.items())
try:
mapping = sorted(mapping)
except TypeError:
pass
for item_key, item_value in mapping:
Run Code Online (Sandbox Code Playgroud)
为了防止排序,我们只需要一些Iterable[Pair]没有的对象.items().
dict_items 是一个完美的候选人.
以下是如何在不影响yaml模块的全局状态的情况下执行此操作:
#Using a custom Dumper class to prevent changing the global state
class CustomDumper(yaml.Dumper):
#Super neat hack to preserve the mapping key order. See https://stackoverflow.com/a/52621703/1497385
def represent_dict_preserve_order(self, data):
return self.represent_dict(data.items())
CustomDumper.add_representer(dict, CustomDumper.represent_dict_preserve_order)
return yaml.dump(component_dict, Dumper=CustomDumper)
Run Code Online (Sandbox Code Playgroud)