ฉันจะแยกวิเคราะห์ไฟล์ YAML ใน Python ได้อย่างไร


คำตอบ:


806

วิธีที่ง่ายและบริสุทธิ์ที่สุดโดยไม่ต้องพึ่งพาส่วนหัว C คือ PyYaml ( เอกสารประกอบ ) ซึ่งสามารถติดตั้งผ่านpip install pyyaml:

#!/usr/bin/env python

import yaml

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

และนั่นคือมัน yaml.load()ฟังก์ชั่นธรรมดายังมีอยู่ แต่yaml.safe_load()ควรเป็นที่ต้องการเสมอเว้นแต่คุณจะต้องระบุการจัดลำดับวัตถุ / การดีซีเรียลไลเซชันโดยพลการอย่างชัดเจนเพื่อหลีกเลี่ยงการแนะนำความเป็นไปได้สำหรับการใช้รหัสโดยอำเภอใจ

หมายเหตุ PyYaml โครงการสนับสนุนรุ่นขึ้นผ่านข้อกำหนด YAML 1.1 หากจำเป็นต้องมีการสนับสนุนข้อมูลจำเพาะ YAML 1.2ให้ดูruamel.yamlตามที่ระบุไว้ในคำตอบนี้


96
ฉันจะเพิ่มว่าถ้าคุณต้องการทำให้เป็นอนุกรม / deserialize วัตถุโดยพลการมันจะดีกว่าที่จะใช้yaml.safe_loadเพราะมันไม่สามารถรันรหัสโดยพลการจากไฟล์ YAML
ternaryOperator

4
Yaml yaml = ใหม่ Yaml (); วัตถุ obj = yaml.load ("a: 1 \ nb: 2 \ nc: \ n - aaa \ n - bbb");
MayTheSchwartzBeWithYou

2
ฉันชอบบทความโดย moose: martin-thoma.com/configuration-files-in-python
SaurabhM

4
คุณอาจต้องติดตั้งแพคเกจ PyYAML ก่อนpip install pyyamlดูโพสต์นี้เพื่อดูตัวเลือกเพิ่มเติมstackoverflow.com/questions/14261614/…
Romain

7
จุดของการจับข้อยกเว้นในตัวอย่างนี้คืออะไร มันจะพิมพ์ต่อไปและมันก็ทำให้ตัวอย่างที่ซับซ้อนมากขึ้น ..
naught101

116

อ่านและเขียนไฟล์ YAML ด้วย Python 2 + 3 (และ 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)

สร้างไฟล์ YAML แล้ว

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

การสิ้นสุดไฟล์ทั่วไป

.yml และ .yaml

ทางเลือก

สำหรับแอปพลิเคชันของคุณข้อมูลต่อไปนี้อาจสำคัญ:

  • สนับสนุนโดยภาษาโปรแกรมอื่น ๆ
  • การอ่าน / เขียนประสิทธิภาพ
  • ความกะทัดรัด (ขนาดไฟล์)

ดูเพิ่มเติม: การเปรียบเทียบรูปแบบการจัดลำดับข้อมูล

ในกรณีที่คุณกำลังมองหาวิธีสร้างไฟล์การกำหนดค่าคุณอาจต้องการอ่านบทความสั้น ๆ ของฉันไฟล์การตั้งค่าใน Python


การส่งออกของฉันบน Windows €คือ ใครรู้เหตุผลหรือไม่
Cloud Cho

ไฟล์มีการเข้ารหัสอะไรบ้าง คุณแน่ใจหรือว่ามันถูกเข้ารหัส utf-8?
Martin Thoma

1
ขอบคุณสำหรับคำแนะนำ ไฟล์ของฉันมีการเข้ารหัส utf-8 ฉันต้องเปลี่ยนบรรทัดรหัสของคุณio.open(doc_name, 'r', encoding='utf8')เพื่ออ่านอักขระพิเศษ YAML เวอร์ชั่น 0.1.7
Cloud Cho

ฮืมน่าสนใจ ฉันจะพยายามทำซ้ำในวันพรุ่งนี้และจะปรับคำถามถ้าทำได้ ขอบคุณ!
Martin Thoma

1
คุณสามารถใช้ในตัวสำหรับการอ่านและเขียนได้โดยไม่ต้องนำเข้าopen(doc_name, ..., encodung='utf8') io
dexteritas

61

หากคุณมี YAML ที่สอดคล้องกับข้อกำหนดของYAML 1.2 (เปิดตัวในปี 2009) คุณควรใช้ruamel.yaml (ข้อจำกัดความรับผิดชอบ: ฉันเป็นผู้เขียนแพ็คเกจดังกล่าว) มันคือชุดซูเปอร์เซ็ตของ PyYAML ซึ่งรองรับ YAML 1.1 ส่วนใหญ่ (จากปี 2005)

หากคุณต้องการที่จะรักษาความคิดเห็นของคุณเมื่อมีการปัดเศษคุณควรใช้ ruamel.yaml

ตัวอย่างการอัพเกรด @ Jon นั้นง่าย:

import ruamel.yaml as yaml

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

ใช้safe_load()นอกเสียจากว่าคุณจะสามารถควบคุมอินพุตได้อย่างเต็มที่ต้องการมัน (ไม่ค่อยจะใช้ในกรณี) และรู้ว่าคุณกำลังทำอะไรอยู่

หากคุณกำลังใช้ pathlib Pathสำหรับจัดการไฟล์คุณควรใช้ API ruamel.yaml แบบใหม่ที่ให้:

from ruamel.yaml import YAML
from pathlib import Path

path = Path('example.yaml')
yaml = YAML(typ='safe')
data = yaml.load(path)

สวัสดี @ อันธพาล ฉันเคยใช้ ruamel แต่มีปัญหากับเอกสารที่ไม่ได้มาตรฐาน ASCII ( UnicodeDecodeError: 'ascii' codec can't decode byte 0xe7 in position 926: ordinal not in range(128)) ฉันได้พยายามตั้ง yaml.encoding เป็น utf-8 แต่ไม่ได้ทำงานเนื่องจากวิธีโหลดใน YAML ยังคงใช้ ascii_decode นี่เป็นข้อบกพร่องหรือไม่?
SnwBr

27

ก่อนติดตั้ง pyyaml ​​โดยใช้ pip3

จากนั้นนำเข้าโมดูล yaml และโหลดไฟล์ลงในพจนานุกรมที่เรียกว่า 'my_dict':

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

นั่นคือทั้งหมดที่คุณต้องการ ตอนนี้ไฟล์ yaml ทั้งหมดอยู่ในพจนานุกรม 'my_dict'


6
นี่เป็นการปิดตัวจัดการไฟล์หรือไม่?
yangmillstheory

2
หากไฟล์ของคุณมีบรรทัด "- hello world" มันไม่เหมาะสมที่จะเรียกตัวแปร my_dict เนื่องจากมันจะมีรายการ หากไฟล์ที่มีแท็กที่เฉพาะเจาะจง (เริ่มต้นด้วย!!python) ก็ยังสามารถเป็นที่ไม่ปลอดภัย (ในขณะที่ harddisc สมบูรณ์เช็ดทำความสะอาด) yaml.load()เพื่อการใช้งาน ดังที่มีการบันทึกไว้อย่างชัดเจนคุณควรทำซ้ำคำเตือนที่นี่ (ในเกือบทุกกรณีyaml.safe_load()สามารถใช้ได้)
Anthon

4
คุณใช้import yamlแต่นั่นไม่ใช่โมดูลในตัวและคุณไม่ได้ระบุว่าเป็นแพ็คเกจใด การใช้งานimport yamlการติดตั้ง Python3 แบบสดใหม่ส่งผลให้ModuleNotFoundError: No module named 'yaml'
cowlinator

11

ตัวอย่าง:


defaults.yaml

url: https://www.google.com

environment.py

from ruamel import yaml

data = yaml.safe_load(open('defaults.yaml'))
data['url']

มันบันทึกเพื่อไม่ปิดกระแส?
qrtLs

3

ฉันใช้ruamel.yaml รายละเอียดและการอภิปรายที่นี่

from ruamel import yaml

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

การใช้งานของruamel.yamlเข้ากันได้ (กับปัญหาที่แก้ไขได้ง่ายบางอย่าง) กับประเพณีเก่าแก่ของ PyYAML และตามที่ระบุไว้ในลิงค์ที่ฉันให้ใช้

from ruamel import yaml

แทน

import yaml

และจะแก้ไขปัญหาส่วนใหญ่ของคุณ

แก้ไข : PyYAML ยังไม่ตายเพราะปรากฎว่าเป็นเพียงการบำรุงรักษาในสถานที่ที่แตกต่างกัน


@Oleksander: PyYaml มีความมุ่งมั่นใน 7 เดือนที่ผ่านมาและปัญหาที่ปิดล่าสุดคือ 12 วันที่ผ่านมา คุณช่วยนิยาม "Long Dead?" ให้หน่อยได้ไหม
abalter

@abalter ฉันขอโทษดูเหมือนว่าฉันได้รับข้อมูลจากเว็บไซต์อย่างเป็นทางการของพวกเขาหรือโพสต์ได้ที่นี่stackoverflow.com/a/36760452/5510526
Oleksandr Zelentsov

@OleksandrZelentsov ฉันเห็นความสับสน มีช่วงเวลา loooong เมื่อมันตาย github.com/yaml/pyyaml/graphs/contributors อย่างไรก็ตามไซต์ของพวกเขากำลังขึ้นและแสดงรุ่นที่โพสต์หลังจากโพสต์ดังกล่าวซึ่งอ้างถึงจุดจบของ PyYaml ดังนั้นจึงมีความเป็นธรรมที่จะบอกว่า ณ จุดนี้มันยังมีชีวิตอยู่ถึงแม้ว่ามันจะมีทิศทางที่สัมพันธ์กับซากปรักหักพังไม่ชัดเจน นอกจากนี้ยังมีการสนทนายาวที่นี่กับโพสต์ล่าสุด ฉันเพิ่มความคิดเห็นและตอนนี้ฉันเป็นเพียงคนเดียว ฉันเดาว่าฉันไม่เข้าใจว่าปัญหาปิดทำงานอย่างไร github.com/yaml/pyyaml/issues/145
abalter

@abalter FWIW เมื่อคำตอบนั้นโพสต์มีการกระทำทั้งหมด 9 ครั้งในอดีตที่ผ่านมา ... อายุต่ำกว่า 7 ปี หนึ่งในนั้นคือ "แก้ไข" โดยอัตโนมัติของไวยากรณ์ที่ไม่ดี ทั้งสองเกี่ยวข้องกับการเปิดตัวรุ่นใหม่ที่แทบจะไม่เปลี่ยน ส่วนที่เหลือเป็น tweaks ที่ค่อนข้างเล็กส่วนใหญ่ทำเมื่อห้าปีก่อนคำตอบ การแก้ไขอัตโนมัติทั้งหมดทำได้โดยบุคคลเดียว ฉันจะไม่ตัดสินคำตอบนั้นอย่างรุนแรงสำหรับการเรียก PyYAML "long dead"
คดีกองทุนของโมนิกา

-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:]))

1
รหัสนี้ไม่ได้ทำอะไรเลย คุณหมายถึงการแสดงความคิดเห็นรหัส?
cowlinator
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.