Điều này sẽ không hoạt động:
hợp nhất chỉ được hỗ trợ bởi các thông số kỹ thuật YAML cho ánh xạ và không cho chuỗi
bạn hoàn toàn trộn mọi thứ bằng cách có một khóa hợp nhất <<
theo sau là dấu phân tách khóa / giá trị :
và một giá trị là tham chiếu rồi tiếp tục với một danh sách ở cùng mức thụt lề
Điều này không đúng YAML:
combine_stuff:
x: 1
- a
- b
Vì vậy, cú pháp ví dụ của bạn thậm chí sẽ không có ý nghĩa như một đề xuất tiện ích mở rộng YAML.
Nếu bạn muốn làm điều gì đó như hợp nhất nhiều mảng, bạn có thể muốn xem xét một cú pháp như:
combined_stuff:
- <<: *s1, *s2
- <<: *s3
- d
- e
- f
nơi s1
, s2
, s3
đang neo trên chuỗi (không hiển thị) mà bạn muốn kết hợp thành một chuỗi mới và sau đó có d
, e
và f
gắn vào đó. Nhưng YAML đang giải quyết loại cấu trúc độ sâu này trước tiên, vì vậy không có ngữ cảnh thực sự có sẵn trong quá trình xử lý khóa hợp nhất. Không có mảng / danh sách nào có sẵn cho bạn để bạn có thể đính kèm giá trị đã xử lý (chuỗi được cố định) vào.
Bạn có thể thực hiện cách tiếp cận như được đề xuất bởi @dreftymac, nhưng điều này có nhược điểm lớn là bằng cách nào đó bạn cần biết chuỗi lồng nhau nào cần làm phẳng (nghĩa là bằng cách biết "đường dẫn" từ gốc của cấu trúc dữ liệu được tải đến chuỗi mẹ), hoặc bạn thực hiện một cách đệ quy cấu trúc dữ liệu đã tải để tìm kiếm các mảng / danh sách lồng nhau và làm phẳng tất cả chúng một cách bừa bãi.
Một giải pháp tốt hơn IMO sẽ là sử dụng các thẻ để tải các cấu trúc dữ liệu làm phẳng cho bạn. Điều này cho phép biểu thị rõ ràng những gì cần làm phẳng và những gì không và cung cấp cho bạn toàn quyền kiểm soát việc làm phẳng này được thực hiện trong quá trình tải hay được thực hiện trong khi truy cập. Chọn cái nào là vấn đề dễ thực hiện và hiệu quả về thời gian và không gian lưu trữ. Đây là sự đánh đổi tương tự cần được thực hiện để triển khai tính năng khóa hợp nhất và không có giải pháp duy nhất nào luôn là tốt nhất.
Ví dụ: ruamel.yaml
thư viện của tôi sử dụng brute force merge-dicts trong quá trình tải khi sử dụng trình tải an toàn của nó, dẫn đến các từ điển được hợp nhất là các loại Python bình thường. Việc hợp nhất này phải được thực hiện trước và sao chép dữ liệu (không gian không hiệu quả) nhưng nhanh chóng trong tra cứu giá trị. Khi sử dụng bộ tải khứ hồi, bạn muốn có thể kết xuất các hợp nhất không hợp nhất, vì vậy chúng cần được giữ riêng biệt. Cơ cấu dữ liệu như dict được tải do tải khứ hồi, hiệu quả về không gian nhưng truy cập chậm hơn, vì nó cần thử và tra cứu một khóa không tìm thấy trong chính dict trong các hợp nhất (và điều này không được lưu vào bộ nhớ đệm, vì vậy nó cần phải được thực hiện mọi lúc). Tất nhiên những cân nhắc như vậy không quan trọng lắm đối với các tệp cấu hình tương đối nhỏ.
Sau đây thực hiện một lược đồ giống như hợp nhất cho các danh sách trong python bằng cách sử dụng các đối tượng có thẻ flatten
mà khi di chuyển sẽ tái sinh thành các mục là danh sách và được gắn thẻ toflatten
. Sử dụng hai thẻ này, bạn có thể có tệp YAML:
l1: &x1 !toflatten
- 1
- 2
l2: &x2
- 3
- 4
m1: !flatten
- *x1
- *x2
- [5, 6]
- !toflatten [7, 8]
(việc sử dụng trình tự kiểu dòng so với khối là hoàn toàn tùy ý và không ảnh hưởng đến kết quả được tải).
Khi lặp lại các mục là giá trị cho khóa, m1
điều này "đệ quy" thành các chuỗi được gắn thẻ toflatten
, nhưng hiển thị các danh sách khác (bí danh hoặc không) dưới dạng một mục duy nhất.
Một cách khả thi với mã Python để đạt được điều đó là:
import sys
from pathlib import Path
import ruamel.yaml
yaml = ruamel.yaml.YAML()
@yaml.register_class
class Flatten(list):
yaml_tag = u'!flatten'
def __init__(self, *args):
self.items = args
@classmethod
def from_yaml(cls, constructor, node):
x = cls(*constructor.construct_sequence(node, deep=True))
return x
def __iter__(self):
for item in self.items:
if isinstance(item, ToFlatten):
for nested_item in item:
yield nested_item
else:
yield item
@yaml.register_class
class ToFlatten(list):
yaml_tag = u'!toflatten'
@classmethod
def from_yaml(cls, constructor, node):
x = cls(constructor.construct_sequence(node, deep=True))
return x
data = yaml.load(Path('input.yaml'))
for item in data['m1']:
print(item)
kết quả đầu ra:
1
2
[3, 4]
[5, 6]
7
8
Như bạn có thể thấy, bạn có thể thấy, trong chuỗi cần làm phẳng, bạn có thể sử dụng bí danh cho một chuỗi được gắn thẻ hoặc bạn có thể sử dụng một chuỗi được gắn thẻ. YAML không cho phép bạn làm:
- !flatten *x2
, tức là gắn thẻ một chuỗi được cố định, vì điều này về cơ bản sẽ biến nó thành một cấu trúc dữ liệu khác.
Sử dụng các thẻ rõ ràng IMO tốt hơn là có một số phép thuật xảy ra như với các khóa hợp nhất YAML <<
. Nếu không có gì khác, bây giờ bạn phải trải qua vòng lặp nếu bạn tình cờ có tệp YAML với ánh xạ có khóa
<<
mà bạn không muốn hoạt động như khóa hợp nhất, ví dụ: khi bạn thực hiện ánh xạ các toán tử C với mô tả của chúng bằng tiếng Anh (hoặc một số ngôn ngữ tự nhiên khác).