Несмотря на то, что «маркировка как отдельных объектов python невозможна», возможно выполнимо пометить их явными тегами даже в рамках ограничений безопасного загрузчика. Это не делает небезопасной загрузку YAML-файла, если только объекты, созданные из этих тегов, не имеют небезопасных побочных эффектов при инициации.
Использование тегов также позволяет вам выгружать (и загружать) структуру данных, которую выхранится в памяти, даже если в какой-то момент в вашей разработке есть ссылки от более чем одного объекта на один конкретный другой объект или когда у вас есть объекты с (косвенными) ссылками на себя. Они будут сбрасываться с помощью якорей и псевдонимов, и нетрудно разрешить эти вещи самостоятельно при сбросе без использования тегов, так как вам нужно будет отслеживать уже сброшенные объекты.
Unittest для отдельных пользователей может быть легконаписано. Обычно единственное, что вы должны убедиться, это то, что вы можете создать сцену без действий, затем вы можете протестировать все для сцены, которая не включает в себя действия и т. Д.
PyYAML может анализировать все YAML 1.1спецификация, но не может загрузить всю эту спецификацию. Кроме того, YAML 1.2 существует уже десять лет. Ни один из них не может быть ограничением для вашей программы, но я рекомендую использовать ruamel.yaml
, у которого нет этих проблем (отказ от ответственности: я являюсь автором этого пакета). Как выгружать / загружать классы с ruamel.yaml
описано здесь
import sys
from pathlib import Path
import ruamel.yaml
data_file = Path('data.yaml')
yaml = ruamel.yaml.YAML(typ='safe')
@yaml.register_class
class Scene:
def __init__(self, sc_parm, actions):
self.sc_parm = sc_parm
self.actions = actions
@yaml.register_class
class Action:
def __init__(self, ac_parm1, ac_parm2):
self.ac_parm1 = ac_parm2
self.ac_parm2 = ac_parm2
shared_action = Action('south', 1)
data = [
Scene('sc1_parm_val', []),
Scene('sc2_parm_val', [Action('north', 3), shared_action]),
Scene('sc3_parm_val', [shared_action, Action('west', 2)]),
]
yaml.dump(data, data_file)
print(data_file.read_text(), end='')
print('=+'*30)
d2 = yaml.load(data_file)
for d in d2:
print(d.sc_parm, d.actions)
, что дает:
- !Scene
actions: []
sc_parm: sc1_parm_val
- !Scene
actions:
- !Action {ac_parm1: 3, ac_parm2: 3}
- &id001 !Action {ac_parm1: 1, ac_parm2: 1}
sc_parm: sc2_parm_val
- !Scene
actions:
- *id001
- !Action {ac_parm1: 2, ac_parm2: 2}
sc_parm: sc3_parm_val
=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
sc1_parm_val []
sc2_parm_val [<__main__.Action object at 0x7f009be56f28>, <__main__.Action object at 0x7f009be56fd0>]
sc3_parm_val [<__main__.Action object at 0x7f009be56fd0>, <__main__.Action object at 0x7f009be56e48>]
Как вы можете видеть из идентификаторов Action
объектов, второе действие второй сцены снова совпадает с первым действием последней сцены (оригинал shared_action
)
Убедитесь, что если вы решите сделать свою собственную from_yaml
(вместо того, чтобы полагаться на значение по умолчанию, которое вы получаете при регистрации), например, чтобы ограничить сбрасываемые атрибуты, вы используете двухэтапный процесс создания ваших объектов, поскольку это необходимо для обеспечения рекурсивных структур данных в вашем дереве. Возможно, вам это не понадобится сразу, но это довольно просто сделать и, например, описать здесь для загрузчика туда и обратно (безопасный загрузчик, который может сохранять комментарии, стили цитирования, псевдонимы и т. Д. При загрузке затемдемпинг ЯМЛ).