Bagaimana saya bisa mem-parsing file YAML dengan Python

611

Bagaimana saya bisa mem-parsing file YAML dengan Python?

Szymon Lipiński
sumber

Jawaban:

806

Metode termudah dan paling murni tanpa mengandalkan header C adalah PyYaml ( dokumentasi ), yang dapat diinstal melalui pip install pyyaml:

#!/usr/bin/env python

import yaml
import json

with open("example.yaml", 'r') as stream:
    try:
        print(yaml.safe_load(stream))
    except yaml.YAMLError as exc:
        print(exc)

Dan itu saja. yaml.load()Fungsi polos juga ada, tetapi yaml.safe_load()harus selalu lebih disukai kecuali jika Anda secara eksplisit membutuhkan serialisasi objek / deserialisasi objek arbitrer yang disediakan untuk menghindari kemungkinan memperkenalkan eksekusi kode arbitrer.

Catatan proyek PyYaml mendukung versi melalui spesifikasi YAML 1.1 . Jika dukungan spesifikasi YAML 1.2 diperlukan, lihat ruamel.yaml sebagaimana tercantum dalam jawaban ini .

Jon
sumber
96
Saya akan menambahkan bahwa kecuali Anda ingin membuat serial / deserialize objek sewenang-wenang, lebih baik digunakan yaml.safe_loadkarena tidak dapat mengeksekusi kode arbitrer dari file YAML.
ternaryOperator
4
Yaml yaml = Yaml baru (); Object obj = yaml.load ("a: 1 \ nb: 2 \ nc: \ n - aaa \ n - bbb");
MayTheSchwartzBeWithYou
2
Saya suka artikel oleh moose: martin-thoma.com/configuration-files-in-python
SaurabhM
4
Anda mungkin perlu menginstal paket PyYAML terlebih dahulu pip install pyyaml, lihat posting ini untuk opsi lebih lanjut stackoverflow.com/questions/14261614/…
Romain
7
Apa gunanya menangkap pengecualian dalam contoh ini? Akan tetap mencetak, dan itu hanya membuat contoh lebih berbelit-belit ..
naught101
116

Baca & Tulis file YAML dengan Python 2 + 3 (dan unicode)

# -*- coding: utf-8 -*-
import yaml
import io

# Define data
data = {
    'a list': [
        1, 
        42, 
        3.141, 
        1337, 
        'help', 
        u'€'
    ],
    'a string': 'bla',
    'another dict': {
        'foo': 'bar',
        'key': 'value',
        'the answer': 42
    }
}

# Write YAML file
with io.open('data.yaml', 'w', encoding='utf8') as outfile:
    yaml.dump(data, outfile, default_flow_style=False, allow_unicode=True)

# Read YAML file
with open("data.yaml", 'r') as stream:
    data_loaded = yaml.safe_load(stream)

print(data == data_loaded)

File YAML dibuat

a list:
- 1
- 42
- 3.141
- 1337
- help
- 
a string: bla
another dict:
  foo: bar
  key: value
  the answer: 42

Ujung file umum

.yml dan .yaml

Alternatif

Untuk aplikasi Anda, berikut ini mungkin penting:

  • Dukungan oleh bahasa pemrograman lain
  • Kinerja membaca / menulis
  • Kekompakan (ukuran file)

Lihat juga: Perbandingan format serialisasi data

Jika Anda mencari cara untuk membuat file konfigurasi, Anda mungkin ingin membaca artikel pendek saya File konfigurasi dalam Python

Martin Thoma
sumber
Output saya pada Windows adalah €. Adakah yang tahu alasannya?
Cloud Cho
Pengkodean apa yang dimiliki file? Anda yakin ini dikodekan utf-8?
Martin Thoma
1
Terima kasih atas sarannya. File saya memiliki encoding utf-8. Saya harus mengubah baris kode Anda io.open(doc_name, 'r', encoding='utf8')untuk membaca karakter khusus. YAML versi 0.1.7
Cloud Cho
Hah, menarik. Saya akan mencoba mereproduksi itu besok dan akan menyesuaikan pertanyaan jika saya bisa. Terima kasih!
Martin Thoma
1
Anda dapat menggunakan bawaan open(doc_name, ..., encodung='utf8')untuk membaca dan menulis, tanpa mengimpor io.
dexteritas
62

Jika Anda memiliki YAML yang sesuai dengan spesifikasi YAML 1.2 (dirilis 2009) maka Anda harus menggunakan ruamel.yaml (penafian: Saya pembuat paket itu). Ini pada dasarnya adalah superset dari PyYAML, yang mendukung sebagian besar YAML 1.1 (dari 2005).

Jika Anda ingin dapat mempertahankan komentar Anda saat bolak-balik, Anda tentu harus menggunakan ruamel.yaml.

Meningkatkan contoh @ Jon mudah:

import ruamel.yaml as yaml

with open("example.yaml") as stream:
    try:
        print(yaml.safe_load(stream))
    except yaml.YAMLError as exc:
        print(exc)

Gunakan safe_load()kecuali Anda benar-benar memiliki kontrol penuh atas input, membutuhkannya (jarang terjadi) dan tahu apa yang Anda lakukan.

Jika Anda menggunakan pathlib Pathuntuk memanipulasi file, Anda lebih baik menggunakan API baru yang disediakan ruamel.yaml:

from ruamel.yaml import YAML
from pathlib import Path

path = Path('example.yaml')
yaml = YAML(typ='safe')
data = yaml.load(path)
Anthon
sumber
Halo @Anthon. Saya menggunakan ruamel tetapi mendapat masalah dengan dokumen yang tidak sesuai dengan ascii ( UnicodeDecodeError: 'ascii' codec can't decode byte 0xe7 in position 926: ordinal not in range(128)). Saya sudah mencoba untuk mengatur yaml.encoding ke utf-8 tetapi tidak berfungsi karena metode load di YAML masih menggunakan ascii_decode. Apakah ini bug?
SnwBr
27

Pertama instal pyyaml ​​menggunakan pip3.

Kemudian impor modul yaml dan muat file ke dalam kamus yang disebut 'my_dict':

import yaml
with open('filename.yaml') as f:
    my_dict = yaml.safe_load(f)

Itu yang kamu butuhkan. Sekarang seluruh file yaml ada di kamus 'my_dict'.

Sahabat
sumber
6
Apakah ini menutup pegangan file?
yangmillstheory
2
Jika file Anda berisi baris "- hello world", tidak pantas untuk memanggil variabel my_dict, karena akan berisi daftar. Jika file itu berisi tag tertentu (dimulai dengan !!python) itu juga bisa tidak aman (seperti dalam harddisk lengkap dihapus bersih) untuk digunakan yaml.load(). Seperti yang didokumentasikan dengan jelas, Anda harus mengulangi peringatan itu di sini (dalam hampir semua kasus yaml.safe_load()dapat digunakan).
Anthon
4
Anda menggunakan import yaml, tetapi itu bukan modul bawaan, dan Anda tidak menentukan paket mana itu. Berjalan import yamlpada hasil instal Python3 baru diModuleNotFoundError: No module named 'yaml'
cowlinator
11

Contoh:


defaults.yaml

url: https://www.google.com

environment.py

from ruamel import yaml

data = yaml.safe_load(open('defaults.yaml'))
data['url']
Prashanth Sams
sumber
Apakah menghemat untuk tidak menutup arus?
qrtLs
3

Saya menggunakan ruamel.yaml . Detail & debat di sini .

from ruamel import yaml

with open(filename, 'r') as fp:
    read_data = yaml.load(fp)

Penggunaan ruamel.yaml kompatibel (dengan beberapa masalah sederhana yang dapat dipecahkan) dengan penggunaan lama PyYAML dan seperti yang dinyatakan dalam tautan yang saya berikan, gunakan

from ruamel import yaml

dari pada

import yaml

dan itu akan memperbaiki sebagian besar masalah Anda.

EDIT : PyYAML tidak mati ternyata, itu hanya dipertahankan di tempat yang berbeda.

Oleksandr Zelentsov
sumber
@Oleksander: PyYaml telah melakukan dalam 7 bulan terakhir, dan masalah tertutup terakhir adalah 12 hari yang lalu. Bisakah Anda mendefinisikan "lama mati?"
abalter
@abalter Saya minta maaf, sepertinya saya mendapat info dari situs resmi mereka atau posting di sini stackoverflow.com/a/36760452/5510526
Oleksandr Zelentsov
@OlexandrZelentsov saya bisa melihat kebingungan. Ada periode loooong ketika sudah mati. github.com/yaml/pyyaml/graphs/contributors . Namun, situs mereka IS up dan menunjukkan rilis yang diposting SETELAH posting SO mengacu pada kematian PyYaml. Jadi wajar untuk mengatakan bahwa pada titik ini masih hidup, meskipun arahnya relatif terhadap ruamel jelas tidak pasti. JUGA, ada diskusi panjang di sini dengan posting terbaru. Saya menambahkan komentar, dan sekarang milik saya satu-satunya. Saya kira saya tidak mengerti bagaimana masalah tertutup bekerja. github.com/yaml/pyyaml/issues/145
abalter
@abalter FWIW, ketika jawaban itu diposting, ada total 9 komitmen di masa lalu ... hanya di bawah 7 tahun. Salah satunya adalah "perbaikan" tata bahasa buruk otomatis. Dua terlibat merilis versi baru yang hampir tidak berubah. Sisanya relatif kecil, sebagian besar dibuat lima tahun sebelum jawaban. Semua kecuali perbaikan otomatis dilakukan oleh satu orang. Saya tidak akan menilai jawaban itu dengan keras karena menyebut PyYAML "sudah lama mati".
Dana Gugatan Monica
-1
#!/usr/bin/env python

import sys
import yaml

def main(argv):

    with open(argv[0]) as stream:
        try:
            #print(yaml.load(stream))
            return 0
        except yaml.YAMLError as exc:
            print(exc)
            return 1

if __name__ == "__main__":
    sys.exit(main(sys.argv[1:]))
Wojciech Sciesinski
sumber
1
Kode ini sebenarnya tidak melakukan apa-apa. Apakah Anda bermaksud mengomentari kode?
cowlinator