Làm cách nào tôi có thể phân tích cú pháp tệp YAML bằng Python


Câu trả lời:


806

Phương pháp đơn giản và thuần túy nhất mà không cần dựa vào tiêu đề C là PyYaml ( tài liệu ), có thể được cài đặt qua 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)

Và đó là nó. Một yaml.load()hàm đơn giản cũng tồn tại, nhưng yaml.safe_load()phải luôn luôn được ưu tiên trừ khi bạn rõ ràng cần tuần tự hóa / giải tuần tự hóa đối tượng được cung cấp để tránh đưa ra khả năng thực thi mã tùy ý.

Lưu ý dự án PyYaml hỗ trợ các phiên bản thông qua đặc tả YAML 1.1 . Nếu cần hỗ trợ đặc tả YAML 1.2 , hãy xem ruamel.yaml như đã lưu ý trong câu trả lời này .


96
Tôi sẽ thêm rằng trừ khi bạn muốn tuần tự hóa / giải tuần tự hóa các đối tượng tùy ý, tốt hơn là sử dụng yaml.safe_loadvì nó không thể thực thi mã tùy ý từ tệp YAML.
ternaryOperator

4
Yaml yaml = new Yaml (); Đối tượng obj = yaml.load ("a: 1 \ nb: 2 \ nc: \ n - aaa \ n - bbb");
MayTheSchwartzBeWithYou

2
Tôi thích bài viết của moose: martin-thoma.com/configuration-files-in-python
SaurabhM

4
Trước tiên, bạn có thể cần cài đặt gói PyYAML pip install pyyaml, xem bài đăng này để biết thêm tùy chọn stackoverflow.com/questions/14261614/iêu
Romain

7
Điểm bắt ngoại lệ trong ví dụ này là gì? Dù sao nó cũng sẽ được in, và nó chỉ làm cho ví dụ trở nên phức tạp hơn ..
naught 101

116

Đọc và ghi tệp YAML bằng Python 2 + 3 (và 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)

Tạo tập tin YAML

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

Kết thúc tập tin phổ biến

.yml.yaml

Lựa chọn thay thế

Đối với ứng dụng của bạn, những điều sau đây có thể quan trọng:

  • Hỗ trợ bởi các ngôn ngữ lập trình khác
  • Hiệu suất đọc / viết
  • Tính gọn nhẹ (kích thước tệp)

Xem thêm: So sánh các định dạng tuần tự hóa dữ liệu

Trong trường hợp bạn muốn tìm cách tạo tệp cấu hình, bạn có thể muốn đọc các tệp Cấu hình bài viết ngắn của tôi bằng Python


Đầu ra của tôi trên Windows là €. Có ai biết lý do không?
Đám mây Cho

Tập tin có mã hóa gì? Bạn có chắc là nó được mã hóa utf-8 không?
Martin Thoma

1
Cảm ơn đề nghị. Tập tin của tôi có mã hóa utf-8. Tôi đã phải thay đổi dòng mã của bạn io.open(doc_name, 'r', encoding='utf8')để đọc ký tự đặc biệt. Phiên bản YAML 0.1.7
Cloud Cho

Hừ, thú vị. Tôi sẽ cố gắng tái tạo vào ngày mai và sẽ điều chỉnh câu hỏi nếu tôi có thể. Cảm ơn bạn!
Martin Thoma

1
Bạn có thể sử dụng tích hợp open(doc_name, ..., encodung='utf8')để đọc và viết mà không cần nhập io.
dexteritas

61

Nếu bạn có YAML phù hợp với đặc điểm kỹ thuật YAML 1.2 (phát hành năm 2009) thì bạn nên sử dụng ruamel.yaml (từ chối trách nhiệm: Tôi là tác giả của gói đó). Nó thực chất là một superset của PyYAML, hỗ trợ hầu hết YAML 1.1 (từ năm 2005).

Nếu bạn muốn có thể giữ bình luận của mình khi bị vấp, bạn chắc chắn nên sử dụng ruamel.yaml.

Nâng cấp ví dụ của @ Jon rất dễ dàng:

import ruamel.yaml as yaml

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

Sử dụng safe_load()trừ khi bạn thực sự có toàn quyền kiểm soát đầu vào, cần nó (hiếm khi xảy ra trường hợp) và biết bạn đang làm gì.

Nếu bạn đang sử dụng pathlib Pathđể thao tác các tệp, bạn nên sử dụng API mới ruamel.yaml cung cấp:

from ruamel.yaml import YAML
from pathlib import Path

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

Xin chào @Anthon. Tôi đã sử dụng ruamel nhưng gặp vấn đề với các tài liệu không tuân thủ ascii ( UnicodeDecodeError: 'ascii' codec can't decode byte 0xe7 in position 926: ordinal not in range(128)). Tôi đã cố gắng đặt yaml.encoding thành utf-8 nhưng không hoạt động vì phương thức tải trong YAML vẫn sử dụng mã ascii_decode. Đây có phải là một lỗi?
SnwBr

27

Đầu tiên cài đặt pyyaml ​​bằng pip3.

Sau đó nhập mô-đun yaml và tải tệp vào một từ điển có tên 'my_dict':

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

Đó là tất cả những gì bạn cần. Bây giờ toàn bộ tệp yaml nằm trong từ điển 'my_dict'.


6
Điều này có đóng tập tin xử lý?
yangmillstheory

2
Nếu tệp của bạn chứa dòng "- hello world" thì không thể gọi biến my_dict, vì nó sẽ chứa danh sách. Nếu tệp đó chứa các thẻ cụ thể (bắt đầu bằng !!python), nó cũng có thể không an toàn (như trong đĩa cứng hoàn toàn bị xóa sạch) để sử dụng yaml.load(). Vì đó là tài liệu rõ ràng, bạn nên lặp lại cảnh báo đó ở đây (trong hầu hết các trường hợp yaml.safe_load()có thể được sử dụng).
Anthon

4
Bạn sử dụng import yaml, nhưng đó không phải là mô-đun tích hợp và bạn không chỉ định gói đó là gì. Chạy import yamltrên bản cài đặt Python3 mới cho kết quảModuleNotFoundError: No module named 'yaml'
cowlinator

11

Thí dụ:


mặc định.yaml

url: https://www.google.com

môi trường

from ruamel import yaml

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

Là tiết kiệm để không đóng luồng?
qrtLs

3

Tôi sử dụng ruamel.yaml . Chi tiết & tranh luận tại đây .

from ruamel import yaml

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

Cách sử dụng ruamel.yaml tương thích (với một số vấn đề có thể giải quyết đơn giản) với cách sử dụng cũ của PyYAML và như đã nêu trong liên kết tôi đã cung cấp, hãy sử dụng

from ruamel import yaml

thay vì

import yaml

và nó sẽ khắc phục hầu hết các vấn đề của bạn.

EDIT : PyYAML không chết vì hóa ra, nó chỉ được duy trì ở một nơi khác.


@Oleksander: PyYaml đã cam kết trong 7 tháng qua và sự cố đóng gần đây nhất là 12 ngày trước. Bạn có thể vui lòng định nghĩa "chết lâu?"
abalter

@abalter Tôi xin lỗi, dường như tôi đã nhận được thông tin từ trang web chính thức của họ hoặc bài đăng ngay tại đây stackoverflow.com/a/36760452/5510526
Oleksandr Zelentsov 20/03/18

@OleksandrZelentsov Tôi có thể thấy sự nhầm lẫn. Có một thời kỳ loooong khi nó đã chết. github.com/yaml/pyyaml/graphs/contologists . Tuy nhiên, trang web của họ đã lên và hiển thị các bản phát hành được đăng SAU bài đăng SO đề cập đến sự sụp đổ của PyYaml. Vì vậy, thật công bằng khi nói rằng tại thời điểm này nó vẫn còn sống, mặc dù hướng của nó so với ruamel rõ ràng là không chắc chắn. CSONG, đã có một cuộc thảo luận dài ở đây với các bài viết gần đây. Tôi đã thêm một bình luận, và bây giờ của tôi là người duy nhất. Tôi đoán tôi không hiểu làm thế nào các vấn đề đóng hoạt động. github.com/yaml/pyyaml/issues/145
abalter

@abalter FWIW, khi câu trả lời đó được đăng, đã có tổng cộng 9 lần cam kết trong quá khứ ... chỉ chưa đầy 7 năm. Một trong số đó là "sửa lỗi" ngữ pháp xấu. Hai liên quan phát hành một phiên bản mới hầu như không thay đổi. Phần còn lại là những điều chỉnh tương đối nhỏ, chủ yếu được thực hiện năm năm trước khi có câu trả lời. Tất cả trừ sửa chữa tự động đã được thực hiện bởi một người. Tôi sẽ không phán xét câu trả lời gay gắt đó vì đã gọi PyYAML là "chết lâu".
Vụ kiện của Quỹ 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:]))

1
Mã này không thực sự làm bất cứ điều gì. Ý của bạn là bình luận ra mã?
chăn bò
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.