#python #yaml #pyyaml #python-dataclasses #ruamel.yaml
#python #yaml #pyyaml #python-классы данных #ruamel.yaml
Вопрос:
У меня есть класс Python примерно так:
from dataclasses import dataclass
from ruamel.yaml import yaml_object, YAML
yaml = YAML()
@yaml_object(yaml)
@dataclass
class DataObject:
normal_attr: str
normal_attr_2: str
conditional_attr: str
Затем я хочу иметь возможность условного сброса conditional_attr
с использованием ruamel.yaml
(который основан на PyYAML) на основе некоторого условия. В идеале это будет работать примерно так:
data = DataObject()
if verbose_output:
yaml.dump(data, stream)
else:
yaml.dump(data, stream, exclude=['conditional_attr'])
Конечно, на самом деле это не работает, но есть ли какой-нибудь способ реализовать это поведение?
Ответ №1:
Я не думаю, что было бы хорошей идеей реализовать исключение определенных ключей сопоставления в качестве опции для метода дампа.
И, кроме того ruamel.yaml
, уже есть документированный метод для создания специальных дампов, которые вы можете использовать для фильтрации любого атрибута, например, для тех, где имя начинается с conditional_
:
import sys
from dataclasses import dataclass
from ruamel.yaml import yaml_object, YAML
yaml = YAML()
verbose_output = False
@yaml_object(yaml)
@dataclass
class DataObject:
normal_attr: str
normal_attr_2: str
conditional_attr: str
@classmethod
def to_yaml(cls, representer, node):
d = {}
for k in node.__annotations__:
if not verbose_output and k.startswith('conditional_attr'):
continue
d[k] = node.__getattribute__(k)
return representer.represent_mapping('!DataObject', d)
data = DataObject(normal_attr='a', normal_attr_2='b', conditional_attr='c')
yaml.dump(data, sys.stdout)
это дает:
!DataObject
normal_attr: a
normal_attr_2: b
Комментарии:
1. Я думаю, было бы идеально указывать поля в момент сериализации. Это то, что делает Marshmallow: marshmallow.readthedocs.io/en/stable /…
2. В любом случае, этот ответ — это начало, но
verbose_output
здесь это глобальная переменная, которая на самом деле не решает мою проблему, потому что вы не можете разумно создать повторно используемый модуль, который позволяет пользователю настраивать детализацию.3.
verbose_output
это глобальная переменная в вашем коде, поэтому я продолжил ее использование здесь. Если у вас есть одна процедура сериализации, добавление аргументов может быть в порядке, но ruamel . yaml (и PyYAML) имеют несколько сериализаций, которые все нуждаются в обновлении с каждым новым параметром, который кто-то придумывает. ИМО гораздо эффективнее сделать это объектно-ориентированным способом, который может использовать каждый сериализатор.4. Если бы мне нужно было что-то подобное, я бы не использовал глобальную переменную, как вы, а добавил атрибут
yaml.verbose_dataclass_output = False
. И создайте альтернативный декоратор дляyaml_object
этого, который по-прежнему принимает экземпляр YAML в качестве параметра, но добавляет метод to_yaml classmethod (который проверяетverbose_data_class
атрибут) к каждому классу, который он украшает.