Saya ingin mendapatkan loader PyYAML untuk memuat pemetaan (dan memesan pemetaan) ke dalam tipe Python 2.7+ OrderedDict , bukan vanilla dict
dan daftar pasangan yang saat ini digunakan.
Apa cara terbaik untuk melakukan itu?
sumber
Saya ingin mendapatkan loader PyYAML untuk memuat pemetaan (dan memesan pemetaan) ke dalam tipe Python 2.7+ OrderedDict , bukan vanilla dict
dan daftar pasangan yang saat ini digunakan.
Apa cara terbaik untuk melakukan itu?
Pembaruan: Dalam python 3.6+ Anda mungkin tidak perlu OrderedDict
sama sekali karena implementasi dikt baru yang telah digunakan dalam pypy untuk beberapa waktu (meskipun dianggap detail implementasi CPython untuk saat ini).
Pembaruan: Dalam python 3.7+, sifat pelestarian sisipan urutan objek didik telah dinyatakan sebagai bagian resmi dari spesifikasi bahasa Python , lihat What's New In Python 3.7 .
Saya suka solusi @James karena kesederhanaannya. Namun, itu mengubah yaml.Loader
kelas global default , yang dapat menyebabkan efek samping yang merepotkan. Terutama, ketika menulis kode perpustakaan ini adalah ide yang buruk. Juga, itu tidak langsung bekerja dengannya yaml.safe_load()
.
Untungnya, solusinya dapat ditingkatkan tanpa banyak usaha:
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)
Untuk serialisasi, saya tidak tahu generalisasi yang jelas, tetapi setidaknya ini seharusnya tidak memiliki efek samping:
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)
Modul yaml memungkinkan Anda menentukan 'perwakilan' khusus untuk mengonversi objek Python menjadi teks dan 'konstruktor' untuk membalikkan proses.
sumber
from six import iteritems
dan kemudian mengubahnyaiteritems(data)
agar berfungsi sama baiknya di Python 2 & 3.represent_dict
danDEFAULT_MAPPING_TAG
) yang tidak berdokumen . Apakah ini karena dokumentasinya tidak lengkap, atau apakah fitur-fitur ini tidak didukung dan dapat berubah tanpa pemberitahuan?dict_constructor
Anda harus meneleponloader.flatten_mapping(node)
atau Anda tidak akan dapat memuat<<: *...
(menggabungkan sintaksis)Opsi 2018:
oyaml
adalah pengganti drop-in untuk PyYAML yang mempertahankan pemesanan dict. Kedua Python 2 dan Python 3 didukung. Cukuppip install oyaml
, dan impor seperti yang ditunjukkan di bawah ini:Anda tidak akan lagi terganggu oleh pemetaan yang kacau saat membuang / memuat.
Catatan: Saya penulis oyaml.
sumber
Opsi 2015 (dan lebih baru):
ruamel.yaml adalah setetes untuk PyYAML (penafian: Saya pembuat paket itu). Mempertahankan urutan pemetaan adalah salah satu hal yang ditambahkan dalam versi pertama (0,1) kembali pada tahun 2015. Tidak hanya mempertahankan urutan kamus Anda, itu juga akan mempertahankan komentar, nama jangkar, tag dan tidak mendukung YAML 1.2 spesifikasi (dirilis 2009)
Spesifikasi mengatakan bahwa pemesanan tidak dijamin, tetapi tentu saja ada pemesanan dalam file YAML dan parser yang sesuai hanya bisa berpegang pada itu dan secara transparan menghasilkan objek yang menjaga pemesanan. Anda hanya perlu memilih parser, loader, dan dumper¹ yang tepat:
akan memberimu:
data
adalah tipeCommentedMap
yang berfungsi seperti dict, tetapi memiliki informasi tambahan yang disimpan hingga dibuang (termasuk komentar yang disimpan!)sumber
CommentedMap
secara langsung tetapi tidak berhasil, danOrderedDict
menempatkan di!!omap
mana-mana yang tidak ramah pengguna.CommentedMap
dengansafe=True
diYAML
, yang tidak bekerja (menggunakansafe=False
karya). Saya juga memiliki masalah denganCommentedMap
tidak dapat dimodifikasi, tetapi saya tidak dapat mereproduksinya sekarang ... Saya akan membuka pertanyaan baru jika saya menemukan masalah ini lagi.yaml = YAML()
, Anda mendapatkan parser / dumper pulang-pergi dan itu adalah turunan dari parser / dumper aman yang tahu tentang CommentedMap / Seq dll.Catatan : ada pustaka, berdasarkan jawaban berikut, yang mengimplementasikan CLoader dan CDumper: Phynix / yamlloader
Saya sangat ragu bahwa ini adalah cara terbaik untuk melakukannya, tetapi ini adalah cara saya datang dengan, dan itu berhasil. Juga tersedia sebagai intisari .
sumber
key_node.start_mark
atribut dalam pesan kesalahan Anda, saya tidak melihat cara yang jelas untuk menyederhanakan loop konstruksi pusat Anda. Jika Anda mencoba memanfaatkan fakta bahwaOrderedDict
konstruktor akan menerima iterable pasangan kunci, nilai, Anda kehilangan akses ke detail itu ketika membuat pesan kesalahan.add_constructor
dalam__init__
metode Anda .Pembaruan : perpustakaan tidak digunakan lagi karena yamlloader (yang didasarkan pada yamlordereddictloader)
Saya baru saja menemukan perpustakaan Python ( https://pypi.python.org/pypi/yamlordereddictloader/0.1.1 ) yang dibuat berdasarkan jawaban atas pertanyaan ini dan cukup mudah digunakan:
sumber
yodl
di github.Di instalasi PyYaml saya untuk Python 2.7 saya memperbarui __init__.py, constructor.py, dan loader.py. Sekarang mendukung opsi object_pairs_hook untuk memuat perintah. Perbedaan perubahan yang saya buat adalah di bawah ini.
sumber
inilah solusi sederhana yang juga memeriksa kunci tingkat atas yang digandakan di peta Anda.
sumber