어디에서 어떻게 YAML 매핑을 OrderedDicts로로드 할 수 있습니까?
PyYAML 의 로더가 바닐라 와 현재 사용중인 쌍 목록 대신 Python 2.7 + OrderedDict 유형으로 매핑 (및 정렬 된 매핑)을로드 하도록하고 싶습니다 dict.
가장 좋은 방법은 무엇입니까?
업데이트 : 파이썬 3.6 이상에서는 한동안 pypy 된에서 사용 새로운 DICT 구현OrderedDict 으로 인해 전혀 필요하지 않을을 구석으로입니다 (지금은 CPython과의 구현 세부 사항을 고려했지만).
업데이트 : 표준 3.7 이상에서 dict 배열의 배열 보존은 언어 사양의 공식 부분으로 선언되었습니다 (Python 3.7의 새로운 기능 참조) .
나는 단순성을 위해 @James 의 솔루션 을 좋아한다 . 그러나 기본 전역 yaml.Loader클래스가 변경 되어 있습니다. 특히 라이브러리 코드를 사용하는 경우 나쁜 생각입니다. 또한 직접 작동하지 않습니다 yaml.safe_load().
많은 노력없이 솔루션을 개선 할 수 있습니다.
import yaml
from collections import OrderedDict
def ordered_load(stream, Loader=yaml.Loader, object_pairs_hook=OrderedDict):
class OrderedLoader(Loader):
pass
def construct_mapping(loader, node):
loader.flatten_mapping(node)
return object_pairs_hook(loader.construct_pairs(node))
OrderedLoader.add_constructor(
yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
construct_mapping)
return yaml.load(stream, OrderedLoader)
# usage example:
ordered_load(stream, yaml.SafeLoader)
제휴 화의 경우 일반화를 모르지만 부작용이 없어야합니다.
def ordered_dump(data, stream=None, Dumper=yaml.Dumper, **kwds):
class OrderedDumper(Dumper):
pass
def _dict_representer(dumper, data):
return dumper.represent_mapping(
yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
data.items())
OrderedDumper.add_representer(OrderedDict, _dict_representer)
return yaml.dump(data, stream, OrderedDumper, **kwds)
# usage:
ordered_dump(data, Dumper=yaml.SafeDumper)
yaml 모듈을 사용하면 사용자 정의 '표현 자'를 지정하여 Python 객체를 텍스트로 변환하고 '생성자'를 사용하여 프로세스를 되돌릴 수 있습니다.
_mapping_tag = yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG
def dict_representer(dumper, data):
return dumper.represent_dict(data.iteritems())
def dict_constructor(loader, node):
return collections.OrderedDict(loader.construct_pairs(node))
yaml.add_representer(collections.OrderedDict, dict_representer)
yaml.add_constructor(_mapping_tag, dict_constructor)
2018 옵션 :
oyamldict 순서를 유지 하는 PyYAML 의 드롭 인 대체품입니다 . Python 2와 Python 3이 모두 지원됩니다. 그냥 pip install oyaml다음과 같이 가져옵니다.
import oyaml as yaml
알림 / 로딩시 나사산 매핑으로 인해 더 이상 짜증이 나지 언어.
참고 : 저는 oyaml의 저자입니다.
2015 이상 옵션 :
ruamel.yaml 은 PyYAML의 대체품입니다 (면책 조항 : 해당 패키지의 저자입니다). 매핑 순서를 유지하는 것은 2015 년에 첫 번째 버전 버전 (0.1)에 추가 된 것 중 하나입니다. 주석, 앵커 이름, 태그도 유지하고 YAML 1.2를 지원합니다. 사양 (2009 년 출시)
표준에 따르면 순서가 보장되지 않지만 YAML 파일에 순서가 지정되지 않습니다. 올바른 파서, 로더 및 덤퍼 ¹ 만 선택하면됩니다.
import sys
from ruamel.yaml import YAML
yaml_str = """\
3: abc
conf:
10: def
3: gij # h is missing
more:
- what
- else
"""
yaml = YAML()
data = yaml.load(yaml_str)
data['conf'][10] = 'klm'
data['conf'][3] = 'jig'
yaml.dump(data, sys.stdout)
당신에게 줄 것이다 :
3: abc
conf:
10: klm
3: jig # h is missing
more:
- what
- else
dataCommentedMapdict처럼 작동 하는 유형 이지만 보존 될 때까지 보존 된 추가 정보가 있습니다 (보존 된 주석 포함).
참고 : CLoader 및 CDumpers도 구현하는 다음 답변을 기반으로 라이브러리가 있습니다. Phynix / yamlloader
나는 최선의 방법이라고 의심하지만, 이것이 내가 생각해 낸 방법이 있습니다. 요점으로 도 계명 계명 제공 됩니다 .
import yaml
import yaml.constructor
try:
# included in standard lib from Python 2.7
from collections import OrderedDict
except ImportError:
# try importing the backported drop-in replacement
# it's available on PyPI
from ordereddict import OrderedDict
class OrderedDictYAMLLoader(yaml.Loader):
"""
A YAML loader that loads mappings into ordered dictionaries.
"""
def __init__(self, *args, **kwargs):
yaml.Loader.__init__(self, *args, **kwargs)
self.add_constructor(u'tag:yaml.org,2002:map', type(self).construct_yaml_map)
self.add_constructor(u'tag:yaml.org,2002:omap', type(self).construct_yaml_map)
def construct_yaml_map(self, node):
data = OrderedDict()
yield data
value = self.construct_mapping(node)
data.update(value)
def construct_mapping(self, node, deep=False):
if isinstance(node, yaml.MappingNode):
self.flatten_mapping(node)
else:
raise yaml.constructor.ConstructorError(None, None,
'expected a mapping node, but found %s' % node.id, node.start_mark)
mapping = OrderedDict()
for key_node, value_node in node.value:
key = self.construct_object(key_node, deep=deep)
try:
hash(key)
except TypeError, exc:
raise yaml.constructor.ConstructorError('while constructing a mapping',
node.start_mark, 'found unacceptable key (%s)' % exc, key_node.start_mark)
value = self.construct_object(value_node, deep=deep)
mapping[key] = value
return mapping
업데이트 : 라이브러리는 yamlloader 를 위해 더 이상 사용되지 않습니다 ( yaml ordersdictloader 를 기반으로 함)
방금 이 질문에, 대한 답변을 기반 작성되었으며 사용으로하기 매우 쉬운 파이썬 라이브러리 ( https://pypi.python.org/pypi/yamlordereddictloader/0.1.1 )를 찾았 습니다.
import yaml
import yamlordereddictloader
datas = yaml.load(open('myfile.yml'), Loader=yamlordereddictloader.Loader)
Python 2.7 용 PyYaml 설치에서 __init__.py, constructor.py 및 loader.py를 업데이트했습니다. 이제로드 명령에 대한 object_pairs_hook 옵션을 지원합니다. 내가 만든 변경 사항의 차이점은 다음과 변경됩니다.
__init__.py
$ diff __init__.py Original
64c64
< def load(stream, Loader=Loader, **kwds):
---
> def load(stream, Loader=Loader):
69c69
< loader = Loader(stream, **kwds)
---
> loader = Loader(stream)
75c75
< def load_all(stream, Loader=Loader, **kwds):
---
> def load_all(stream, Loader=Loader):
80c80
< loader = Loader(stream, **kwds)
---
> loader = Loader(stream)
constructor.py
$ diff constructor.py Original
20,21c20
< def __init__(self, object_pairs_hook=dict):
< self.object_pairs_hook = object_pairs_hook
---
> def __init__(self):
27,29d25
< def create_object_hook(self):
< return self.object_pairs_hook()
<
54,55c50,51
< self.constructed_objects = self.create_object_hook()
< self.recursive_objects = self.create_object_hook()
---
> self.constructed_objects = {}
> self.recursive_objects = {}
129c125
< mapping = self.create_object_hook()
---
> mapping = {}
400c396
< data = self.create_object_hook()
---
> data = {}
595c591
< dictitems = self.create_object_hook()
---
> dictitems = {}
602c598
< dictitems = value.get('dictitems', self.create_object_hook())
---
> dictitems = value.get('dictitems', {})
loader.py
$ diff loader.py Original
13c13
< def __init__(self, stream, **constructKwds):
---
> def __init__(self, stream):
18c18
< BaseConstructor.__init__(self, **constructKwds)
---
> BaseConstructor.__init__(self)
23c23
< def __init__(self, stream, **constructKwds):
---
> def __init__(self, stream):
28c28
< SafeConstructor.__init__(self, **constructKwds)
---
> SafeConstructor.__init__(self)
33c33
< def __init__(self, stream, **constructKwds):
---
> def __init__(self, stream):
38c38
< Constructor.__init__(self, **constructKwds)
---
> Constructor.__init__(self)
5 년 전에 열린 주제에 대한 PyYAML 티켓 이 있습니다 . 이 질문에 대한 링크를 포함하여 몇 가지 관련 링크가 포함되어 있습니다. 나는 개인적으로 요점 317164를 포함 된 구현이 아닌 Python 2.7의 OrderedDict 를 사용하여 약간 수정했습니다 (클래스를 from collections import OrderedDict.
여기지도에서 일련의 최상위 키를 확인하는 간단한 솔루션이 있습니다.
import yaml
import re
from collections import OrderedDict
def yaml_load_od(fname):
"load a yaml file as an OrderedDict"
# detects any duped keys (fail on this) and preserves order of top level keys
with open(fname, 'r') as f:
lines = open(fname, "r").read().splitlines()
top_keys = []
duped_keys = []
for line in lines:
m = re.search(r'^([A-Za-z0-9_]+) *:', line)
if m:
if m.group(1) in top_keys:
duped_keys.append(m.group(1))
else:
top_keys.append(m.group(1))
if duped_keys:
raise Exception('ERROR: duplicate keys: {}'.format(duped_keys))
# 2nd pass to set up the OrderedDict
with open(fname, 'r') as f:
d_tmp = yaml.load(f)
return OrderedDict([(key, d_tmp[key]) for key in top_keys])
참고 URL : https://stackoverflow.com/questions/5121931/in-python-how-can-you-load-yaml-mappings-as-orderdicts
'IT' 카테고리의 다른 글
| iPad 브라우저 너비 및 높이 표준 (0) | 2020.07.10 |
|---|---|
| Visual Studio에서 조건부 중단 점을 설정하는 방법은 무엇입니까? (0) | 2020.07.10 |
| 라이브러리와 바이너리가 모두있는 녹 패키지? (0) | 2020.07.10 |
| 사용중인 Entity Framework 버전을 확인하고? (0) | 2020.07.10 |
| html5 비디오 태그에서 소스 변경 (0) | 2020.07.10 |