Bu işe yaramayacak:
birleştirme yalnızca eşlemeler için YAML spesifikasyonları tarafından desteklenir, diziler için desteklenmez
Bir birleştirme anahtarına ve <<
ardından anahtar / değer ayırıcısına :
ve referans olan bir değere sahip olarak şeyleri tamamen karıştırıyorsunuz ve ardından aynı girinti düzeyinde bir listeyle devam ediyorsunuz
Bu doğru YAML değil:
combine_stuff:
x: 1
- a
- b
Dolayısıyla, örnek söz diziminiz bir YAML uzantısı önerisi olarak bile mantıklı olmayacaktır.
Birden çok diziyi birleştirmek gibi bir şey yapmak istiyorsanız, aşağıdaki gibi bir sözdizimi düşünebilirsiniz:
combined_stuff:
- <<: *s1, *s2
- <<: *s3
- d
- e
- f
burada s1
, s2
, s3
yeni bir dizi halinde birleştirme istiyor ve sahip olduğu dizileri (gösterilmemiştir) ile çapa olan d
, e
ve f
buna ekli. Ancak YAML önce bu tür yapıları derinlemesine çözüyor, bu nedenle birleştirme anahtarının işlenmesi sırasında gerçek bir bağlam mevcut değil. İşlenen değeri (bağlantılı sıra) ekleyebileceğiniz bir dizi / liste mevcut değildir.
Yaklaşımı @dreftymac tarafından önerildiği gibi alabilirsiniz, ancak bu büyük bir dezavantaja sahiptir, bir şekilde hangi iç içe dizilerin düzleştirileceğini bilmeniz gerekir (yani, yüklenen veri yapısının kökünden ana diziye giden "yolu" bilmek), ya da iç içe dizileri / listeleri aramak için yüklü veri yapısını yinelemeli olarak yürüdüğünüz ve ayrım gözetmeksizin hepsini düzleştirdiğiniz.
Daha iyi bir çözüm IMO, sizin için düzleştirmeyi yapan veri yapılarını yüklemek için etiketleri kullanmak olacaktır. Bu, neyin düzleştirilmesi gerektiğini ve neyin düzleştirilmeyeceğini açıkça belirtmenize olanak tanır ve bu düzleştirmenin yükleme sırasında mı yoksa erişim sırasında mı yapılacağı konusunda size tam kontrol sağlar. Hangisini seçeceğiniz, zaman ve depolama alanında uygulama kolaylığı ve verimlilik meselesidir. Bu, birleştirme anahtarı özelliğini uygulamak için yapılması gereken aynı ödünleşmedir ve her zaman en iyi olan tek bir çözüm yoktur.
Örneğin, ruamel.yaml
kütüphanem güvenli yükleyicisini kullanırken yükleme sırasında kaba kuvvet birleştirme kurallarını kullanıyor, bu da normal Python sözlükleri olan birleştirilmiş sözlüklerle sonuçlanıyor. Bu birleştirme önceden yapılmalıdır ve verileri çoğaltır (alan verimsizdir) ancak değer aramasında hızlıdır. Gidiş-dönüş yükleyiciyi kullanırken, birleştirmeleri birleştirmeden atabilmek istersiniz, bu yüzden ayrı tutulmaları gerekir. Gidiş-dönüş yüklemenin bir sonucu olarak yüklenen veri yapısı gibi dikte, alan açısından verimli ancak erişimde daha yavaştır, çünkü birleşmelerde diktede bulunmayan bir anahtarı denemek ve aramak zorundadır (ve bu önbelleğe alınmaz, bu nedenle her seferinde yapılması gerekir). Elbette bu tür düşünceler, nispeten küçük yapılandırma dosyaları için çok önemli değildir.
Aşağıdakiler flatten
, python'daki listeler için, anında listelenmiş ve etiketlenmiş öğelere dönüşen etiketli nesneleri kullanarak birleştirme benzeri bir şema uygular toflatten
. Bu iki etiketi kullanarak YAML dosyasına sahip olabilirsiniz:
l1: &x1 !toflatten
- 1
- 2
l2: &x2
- 3
- 4
m1: !flatten
- *x1
- *x2
- [5, 6]
- !toflatten [7, 8]
(akışa karşı blok tarzı dizilerin kullanımı tamamen keyfidir ve yüklenen sonuç üzerinde hiçbir etkisi yoktur).
Anahtar için değer olan öğeler üzerinde yineleme yapıldığında, m1
bu toflatten
, ile etiketlenmiş dizilere "yinelenir" , ancak diğer listeleri (takma ad olan veya olmayan) tek bir öğe olarak görüntüler.
Python kodu ile bunu başarmanın olası bir yolu şudur:
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)
hangi çıktılar:
1
2
[3, 4]
[5, 6]
7
8
Gördüğünüz gibi, düzleştirilmesi gereken dizide, etiketli bir dizinin takma adını kullanabilir veya etiketli bir sıra kullanabilirsiniz. YAML şunları yapmanıza izin vermiyor:
- !flatten *x2
yani bağlantılı bir sekansı etiketleyin, çünkü bu onu esasen farklı bir veri yapısına dönüştürür.
Açık etiketleri kullanmak IMO, YAML birleştirme anahtarlarında olduğu gibi bazı sihirlere sahip olmaktan daha iyidir <<
. Başka bir şey yoksa <<
, bir birleştirme anahtarı gibi davranmak istemediğiniz bir anahtarı olan bir eşlemeye sahip bir YAML dosyanız varsa, örneğin, açıklamalarına C operatörlerinin bir eşlemesini yaptığınızda, çemberlerden geçmek zorunda kalırsınız.
İngilizce (veya başka bir doğal dilde).