В долго выполняющейся программе / процессе P действительно нет необходимости перечитывать данные.Есть несколько вещей, которые нужно иметь в виду:
Если вы используете документ YAML в других программах только тогда, когда P остановлен, то вам нужно только выписать файл при выходе из P.Возможно, вы захотите сделать это, используя atexit
, если у вас нет единой точки выхода
Если другие программы могут редактировать / обновлять список, пока Pвыполняется, затем убедитесь, что вы проверили отметку даты и времени файла YAML и перечитали файл перед добавлением нового контакта.При необходимости вы можете работать с блокировками, чтобы убедиться, что одновременно обновляется только одна программа.
Если для других программ требуется обновленный документ YAML, вы можетелибо выписывайте YAML при каждом обновлении, либо вы можете использовать какой-то механизм для уведомления P о необходимости написания документа YAML.Для этого я использовал обработку SIGINT и связь на основе zeromq.
Многое из вышеперечисленного сделано для вас, если вы используете реальную базу данных, и дляпростая таблица записей, которые имеют одинаковые поля, что может быть лучшей альтернативой.Однако, как только все становится более сложным: разные поля для каждой записи, сложные и возможные рекурсивные данные, многие базы данных (SQL) становятся дополнительной проблемой, а не помогают решить ту, которую вы пытаетесь решить.
ruamel.yaml.base
(отказ от ответственности: я являюсь автором этого пакета) выполняет пункт 2) для вас из коробки, остальные два элемента также легко реализуются.Единственная хитрость заключается в том, что YAMLBase
обычно ожидает сопоставление / dict на корневом уровне для нового файла, поэтому необходимо некоторое принуждение, когда файл еще не существует.
После того, как вы это сделаетеpip install ruamel.yaml.base
:
import os
import ruamel.yaml
from ruamel.yaml.base import YAMLBase
yaml_path = 'contacts.yaml'
class Contacts(YAMLBase):
def __init__(self, path=yaml_path, verbose=0):
self._create_ok = True # so the file is auto created if it doesn't exists
super().__init__(path=path, verbose=verbose)
if not os.path.exists(yaml_path):
# this is necessary to force block style sequence at the top
self._data = ruamel.yaml.comments.CommentedSeq()
self._changed = True
def add_record(self, contact):
self.data.append(contact)
self._changed = True # this signals that writing is necessary
def dump_file(self):
"""dump the contents of the file on disc"""
print('dumping: "{}"'.format(self._path))
with open(yaml_path) as fp:
print(fp.read(), end='')
data1 = {'name' :'Abcd', 'phone': 1234, 'email': 'abcd@gmail.com'}
data2 = {'name': 'efgh', 'phone': 5678, 'email': 'efgh@gmail.com'}
contacts = Contacts()
contacts.add_record(data1)
contacts.save() # optional
contacts.dump_file()
# this is just for checking
contacts.add_record(data2)
contacts.save()
contacts.dump_file()
, что дает:
dumping: "contacts.yaml"
- name: Abcd
phone: 1234
email: abcd@gmail.com
dumping: "contacts.yaml"
- name: Abcd
phone: 1234
email: abcd@gmail.com
- name: efgh
phone: 5678
email: efgh@gmail.com
Если вы установите для параметра verbose
значение 1
, вы получите некоторую информацию о stdout о том, что происходитв пакете.
Если у вас много записей, вы можете изменить self.data
в Contacts
на self.fast_data
, тогда будет загружен YAML с использованием гораздо более быстрого загрузчика на основе Си,за счет невозможности сохранить (добавленные вручную) комментарии и т. д. во входном YAML.(В любом случае используется «safe_load»).