আমি পাইওয়ামএল এর লোডারকে ম্যাপিংগুলি লোড করার জন্য (এবং ম্যাপিংগুলি অর্ডার দিয়েছি ) পাইথন ২.7+ অর্ডারডিক্ট টাইপের পরিবর্তে ভ্যানিলা dict
এবং বর্তমানে যে জোড়গুলির ব্যবহার করছে তার তালিকার পরিবর্তে পেতে চাই ।
এটি করার সর্বোত্তম উপায় কী?
আমি পাইওয়ামএল এর লোডারকে ম্যাপিংগুলি লোড করার জন্য (এবং ম্যাপিংগুলি অর্ডার দিয়েছি ) পাইথন ২.7+ অর্ডারডিক্ট টাইপের পরিবর্তে ভ্যানিলা dict
এবং বর্তমানে যে জোড়গুলির ব্যবহার করছে তার তালিকার পরিবর্তে পেতে চাই ।
এটি করার সর্বোত্তম উপায় কী?
উত্তর:
আপডেট: পাইথন ৩.6++- তে পাইপিতে কিছু সময়ের জন্য ব্যবহৃত নতুন ডিক প্রয়োগেরOrderedDict
কারণে সম্ভবত আপনার মোটেই প্রয়োজন হবে না (যদিও আপাতত সিপিথন বাস্তবায়ন বিশদ বিবেচনা করা হয়)।
আপডেট: পাইথন ৩.7++ তে ডিক অবজেক্টের সন্নিবেশ-আদেশ সংরক্ষণের প্রকৃতিটি পাইথন ল্যাঙ্গুয়েজ অনুচ্ছেদের অফিসিয়াল অংশ হিসাবে ঘোষণা করা হয়েছে , পাইথন ৩. In-এ নতুন কী রয়েছে তা দেখুন ।
সরলতার জন্য আমি @ জেমসের সমাধানটি পছন্দ করি । তবে এটি ডিফল্ট গ্লোবাল 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)
ইয়ামল মডিউল আপনাকে পাইথন অবজেক্টগুলিকে পাঠ্যে রূপান্তর করতে কাস্টম 'ডিপ্রেজেন্টার্স' এবং প্রক্রিয়াটি বিপরীতে 'কনস্ট্রাক্টর' নির্দিষ্ট করার অনুমতি দেয়।
_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)
from six import iteritems
এবং তারপরে এটিকে এমন পরিবর্তন করুন iteritems(data)
যাতে এটি পাইথন 2 এবং 3 তে সমানভাবে কার্যকর হয়
represent_dict
এবং DEFAULT_MAPPING_TAG
) এর অননুমোদিত বৈশিষ্ট্যগুলি ব্যবহার করছে বলে মনে হচ্ছে । এটি কি কারণ ডকুমেন্টেশন অসম্পূর্ণ, বা এই বৈশিষ্ট্যগুলি অসমর্থিত এবং বিজ্ঞপ্তি ছাড়াই পরিবর্তিত হতে পারে?
dict_constructor
আপনাকে কল loader.flatten_mapping(node)
করতে হবে অথবা আপনি লোড করতে পারবেন না <<: *...
(সিনট্যাক্স মার্জ করে)
oyaml
পাইওয়ামএল -এর একটি ড্রপ-ইন প্রতিস্থাপন যা ডিক্ট অর্ডার সংরক্ষণ করে। পাইথন 2 এবং পাইথন 3 উভয়ই সমর্থিত। ঠিক আছে pip install oyaml
, এবং নীচে প্রদর্শিত হিসাবে আমদানি করুন:
import oyaml as yaml
ডাম্পিং / লোড করার সময় আপনি আর স্ক্রু-আপ ম্যাপিংগুলিতে বিরক্ত হবেন না।
দ্রষ্টব্য: আমি oyaml এর লেখক।
রুয়ামেল.আইএমএল হল পাইওয়ামএল- এর প্রতিস্থাপনের ড্রপ (দাবি অস্বীকার: আমি সেই প্যাকেজের লেখক)। ২০১৫ সালে ফিরে প্রথম সংস্করণে (০.১) ম্যাপিংয়ের ক্রম সংরক্ষণ করা ছিল one স্পেসিফিকেশন (২০০৯ প্রকাশিত)
স্পেসিফিকেশন বলছে যে অর্ডারিং গ্যারান্টিযুক্ত নয়, তবে অবশ্যই ওয়াইএএমএল ফাইলে অর্ডার রয়েছে এবং উপযুক্ত পার্সার কেবল এটি ধরে রাখতে পারে এবং স্বচ্ছভাবে অর্ডার রাখে এমন একটি বস্তু তৈরি করতে পারে। আপনাকে কেবল সঠিক পার্সার, লোডার এবং ডাম্পার বেছে নিতে হবে:
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
data
CommentedMap
ডিকের মতো যা কাজ করে তা ধরণের , তবে অতিরিক্ত তথ্য যা ডাম্প হওয়া পর্যন্ত রাখা হয় (সংরক্ষিত মন্তব্য সহ!)
CommentedMap
সরাসরি ব্যবহার করার চেষ্টা করেছি কিন্তু এটি কার্যকর হয় না এবং সর্বত্র OrderedDict
রাখে !!omap
যা খুব ব্যবহারকারী-বান্ধব নয়।
CommentedMap
দিয়ে safe=True
মধ্যে YAML
যা কাজ করে নি, (ব্যবহার safe=False
কাজ)। CommentedMap
পরিবর্তনযোগ্য না হওয়ার বিষয়ে আমারও সমস্যা ছিল , তবে আমি এখনই এটি পুনরুত্পাদন করতে পারি না ... আমি যদি আবার এই সমস্যাটির মুখোমুখি হই তবে আমি একটি নতুন প্রশ্ন খুলব।
yaml = YAML()
, আপনি রাউন্ড-ট্রিপ পার্সার / ডাম্পার পান এবং এটি সেফ পার্সার / ডাম্পার থেকে প্রাপ্ত যে মন্তব্য করা ম্যাপ / সিক ইত্যাদি সম্পর্কে জানে
দ্রষ্টব্য : নীচের উত্তরের উপর ভিত্তি করে একটি গ্রন্থাগার রয়েছে, যা ক্লোয়ডার এবং সিডিম্পারগুলি প্রয়োগ করে: ফিনিক্স / ইয়ামলোডার
আমি খুব সন্দেহ করি যে এটি করার সর্বোত্তম উপায় এটি তবে আমি এইভাবেই এগিয়ে এসেছি এবং এটি কাজ করে। গিস্ট হিসাবেও উপলব্ধ ।
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
key_node.start_mark
নিজের ত্রুটি বার্তায় বৈশিষ্ট্যটি অন্তর্ভুক্ত করতে চান তবে আমি আপনার কেন্দ্রীয় নির্মাণ লুপটি সরল করার কোনও সুস্পষ্ট উপায় দেখতে পাচ্ছি না। যদি আপনি এই সত্যটি ব্যবহারের চেষ্টা করেন যে OrderedDict
কনস্ট্রাক্টর কী, মান জোড়ার একটি পুনরাবৃত্তিযোগ্য গ্রহণ করবে, ত্রুটি বার্তা উত্পন্ন করার সময় আপনি সেই বিশদটির অ্যাক্সেস হারিয়ে ফেলেন।
add_constructor
নিজের __init__
পদ্ধতিতে দ্বিতীয় কলটি সরাতে পারেন ।
আপডেট : গ্রন্থাগারটি ইয়ামলোএডার (যা ইয়ামলর্ডারডিক্ট্রোডারের উপর ভিত্তি করে) এর পক্ষে অবমুক্ত করা হয়েছিল
আমি এইমাত্র একটি পাইথন গ্রন্থাগার পেয়েছি ( https://pypi.python.org/pypi/yamlordereddictloader/0.1.1 ) যা এই প্রশ্নের উত্তরের ভিত্তিতে তৈরি হয়েছিল এবং এটি ব্যবহার করা বেশ সহজ:
import yaml
import yamlordereddictloader
datas = yaml.load(open('myfile.yml'), Loader=yamlordereddictloader.Loader)
yodl
গিথুব দেখুন।
পাইথন ২.7 এর জন্য পাইওয়ামাল ইনস্টলের জন্য আমি __init__.py, কনস্ট্রাক্টর.পি এবং লোডার.পি আপডেট করেছি। এখন লোড কমান্ডের জন্য অবজেক্ট_পেইস_হুক বিকল্পটি সমর্থন করে। আমার করা বিভিন্ন পরিবর্তনের নীচে রয়েছে।
__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)
এখানে একটি সাধারণ সমাধান যা আপনার মানচিত্রে ডুপ্লিকেটড শীর্ষ স্তরের কীগুলিও পরীক্ষা করে।
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])