[PYTHON] 파이썬에서는 YAML 매핑을 OrderedDicts로 어떻게로드 할 수 있습니까?
PYTHON파이썬에서는 YAML 매핑을 OrderedDicts로 어떻게로드 할 수 있습니까?
필자는 PyYAML의 로더가 바닐라 dict와 현재 사용되는 쌍 목록 대신 Python 2.7 + OrderedDict 형식으로 매핑 (및 순서가 매겨진 매핑)을로드하도록하고 싶습니다.
그렇게하는 가장 좋은 방법은 무엇입니까?
해결법
-
==============================
1.업데이트 : 파이썬 3.6 +에 대해서는 새로운 dict 구현으로 인해 특별한 것을 필요로하지 않을 것입니다 (CPython 구현 세부 사항은 현재 고려하고 있습니다).
업데이트 : 파이썬 3.6 +에 대해서는 새로운 dict 구현으로 인해 특별한 것을 필요로하지 않을 것입니다 (CPython 구현 세부 사항은 현재 고려하고 있습니다).
나는 단순함 때문에 @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)
-
==============================
2.yaml 모듈을 사용하면 Python 객체를 텍스트로 변환하고 '생성자'를 사용하여 프로세스를 되돌릴 수있는 사용자 지정 '표현 자'를 지정할 수 있습니다.
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)
-
==============================
3.oyaml은 dict ordering을 유지하는 PyYAML을 대체합니다. 파이썬 2와 파이썬 3 모두 지원됩니다. 그냥 oyaml을 설치하고 아래와 같이 가져 오기하십시오 :
oyaml은 dict ordering을 유지하는 PyYAML을 대체합니다. 파이썬 2와 파이썬 3 모두 지원됩니다. 그냥 oyaml을 설치하고 아래와 같이 가져 오기하십시오 :
import oyaml as yaml
덤프 /로드 할 때 스크류 - 업 맵핑으로 더 이상 짜증을 내지 않습니다.
참고 : 나는 oyaml의 저자입니다.
-
==============================
4.ruamel.yaml은 PyYAML을 대체하는 드롭입니다 (면책 조항 : 나는 그 패키지의 저자입니다). 매핑의 순서를 유지하는 것은 2015 년 첫 번째 버전 (0.1)에 추가 된 항목 중 하나였습니다. 사전의 순서를 유지할뿐만 아니라 주석, 앵커 이름, 태그를 보존하고 YAML 1.2를 지원합니다 사양 (2009 년 출시)
ruamel.yaml은 PyYAML을 대체하는 드롭입니다 (면책 조항 : 나는 그 패키지의 저자입니다). 매핑의 순서를 유지하는 것은 2015 년 첫 번째 버전 (0.1)에 추가 된 항목 중 하나였습니다. 사전의 순서를 유지할뿐만 아니라 주석, 앵커 이름, 태그를 보존하고 YAML 1.2를 지원합니다 사양 (2009 년 출시)
사양에서는 순서가 보장되지는 않지만 물론 YAML 파일에 순서가 있고 적절한 파서가이를 유지하고 순서를 유지하는 객체를 투명하게 생성 할 수 있다고합니다. 올바른 파서, 로더 및 덤퍼를 선택하기 만하면됩니다 .¹ :
import sys import ruamel.yaml as yaml yaml_str = """\ 3: abc conf: 10: def 3: gij # h is missing more: - what - else """ data = yaml.load(yaml_str, Loader=yaml.RoundTripLoader) data['conf'][10] = 'klm' data['conf'][3] = 'jig' yaml.dump(data, sys.stdout, Dumper=yaml.RoundTripDumper)
당신을 줄 것입니다 :
3: abc conf: 10: klm 3: jig # h is missing more: - what - else
데이터는 Dict처럼 작동하는 CommentedMap 유형이지만 덤프 될 때까지 보존되는 추가 정보가 있습니다 (보존 된 주석 포함).
-
==============================
5.참고 : CLoader 및 CDumpers를 구현하는 다음 답변을 기반으로하는 라이브러리가 있습니다. Phynix / yamlloader
참고 : 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
-
==============================
6.업데이트 : 라이브러리는 yamlloader (yamlordereddictloader를 기반으로 함)를 사용하여 더 이상 사용되지 않습니다.
업데이트 : 라이브러리는 yamlloader (yamlordereddictloader를 기반으로 함)를 사용하여 더 이상 사용되지 않습니다.
방금 파이썬 라이브러리 (https://pypi.python.org/pypi/yamlordereddictloader/0.1.1)를 찾았습니다.이 라이브러리는이 질문에 대한 답변을 기반으로 작성되었으며 매우 사용하기 쉽습니다.
import yaml import yamlordereddictloader datas = yaml.load(open('myfile.yml'), Loader=yamlordereddictloader.Loader)
-
==============================
7.Python 2.7 용 PyYaml 설치에서 __init__.py, constructor.py 및 loader.py를 업데이트했습니다. 이제 load 명령에 대한 object_pairs_hook 옵션을 지원합니다. 내가 만든 변경 사항의 차이점은 다음과 같습니다.
Python 2.7 용 PyYaml 설치에서 __init__.py, constructor.py 및 loader.py를 업데이트했습니다. 이제 load 명령에 대한 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)
-
==============================
8.5 년 전에 개설 된 주제에 PyYAML 티켓이 있습니다. 이 질문에 대한 링크를 포함하여 몇 가지 관련 링크가 있습니다. 개인적으로 317164를 골라서 포함 된 구현이 아닌 Python 2.7에서 OrderedDict를 사용하기 위해 약간 수정했습니다 (컬렉션 가져 오기 OrderedDict에서 클래스를 대체했습니다).
5 년 전에 개설 된 주제에 PyYAML 티켓이 있습니다. 이 질문에 대한 링크를 포함하여 몇 가지 관련 링크가 있습니다. 개인적으로 317164를 골라서 포함 된 구현이 아닌 Python 2.7에서 OrderedDict를 사용하기 위해 약간 수정했습니다 (컬렉션 가져 오기 OrderedDict에서 클래스를 대체했습니다).
-
==============================
9.지도의 중복 된 최상위 키를 확인하는 간단한 솔루션이 있습니다.
지도의 중복 된 최상위 키를 확인하는 간단한 솔루션이 있습니다.
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])
from https://stackoverflow.com/questions/5121931/in-python-how-can-you-load-yaml-mappings-as-ordereddicts by cc-by-sa and MIT license
'PYTHON' 카테고리의 다른 글
[PYTHON] IP가 파이썬 2.x에서 네트워크에 있는지 어떻게 확인할 수 있습니까? (0) | 2018.10.03 |
---|---|
[PYTHON] id () 함수는 무엇을 위해 사용됩니까? (0) | 2018.10.03 |
[PYTHON] numpy 배열을 통해 함수를 매핑하는 가장 효율적인 방법 (0) | 2018.10.03 |
[PYTHON] sys.stdout.flush () 메서드 사용 (0) | 2018.10.03 |
[PYTHON] 바이너리 실행 파일로 파이썬 스크립트를 컴파일하는 법 (0) | 2018.10.03 |