首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PyYAML文件高效管理

PyYAML文件高效管理
EN

Stack Overflow用户
提问于 2018-09-16 08:37:57
回答 1查看 132关注 0票数 1

我正在编写一个Python程序,它维护一个联系人列表,每个联系人有3个字段:

  1. 名字
  2. 电话号码
  3. 电子邮件

联系人需要保存在YAML结构化文件中,程序应该提供添加新联系人的便利。

我的代码是:

代码语言:javascript
复制
class contacts:
    def add_contact(self,file,contact):
        if not os.path.exists(file):
            #Creating for the first time
            temp = []
            temp.append(contact)
            with open(file, "w") as file_desc:
                yaml.dump(temp, file_desc, default_flow_style=False)
            file_desc.close()
        else:
            #Second onwards
            with open(file, "r") as file_desc:
                loaded = yaml.safe_load(file_desc)
                loaded.append(contact)
                with open(file, "w") as file_desc2:
                    yaml.dump(loaded, file_desc2, default_flow_style=False)
                    file_desc2.close()
            file_desc.close()

if __name__ == "__main__":

    data1 = {'name' :'Abcd', 'phone': 1234, 'email': 'abcd@gmail.com'}
    data2 = {'name': 'efgh', 'phone': 5678, 'email': 'efgh@gmail.com'}
    contact = contacts()
    contact.add_contact("contacts.yaml", data1)
    contact.add_contact("contacts.yaml",data2)

我认为这是一个低效率的实施。如果我们有100万联系人,并且我们想要添加一个新的联系人,这将首先读取所有的联系人,在列表中添加一个,并再次写入所有的100万+1联系人。有没有一种方法只是添加新的联系人,而不必再次写入整个文件。我想阅读是很重要的,因为我不想存储重复的联系人,这将需要比较。任何其他有效的办法也将受到赞赏。

EN

回答 1

Stack Overflow用户

发布于 2018-09-16 10:14:56

在长时间运行的程序/进程P中,确实没有必要重新读取数据。有几件事要记住:

  1. 如果仅在P停止时在其他程序中使用YAML文档,则只需要在P退出时写出该文件。如果您没有一个出口点,您可能需要使用atexit来执行此操作。
  2. 如果其他程序可能在P运行时编辑/更新列表,则请确保在添加新联系人之前检查YAML文件的日期时间戳并重新读取该文件。如果有必要,您可以使用锁来确保一次只更新一个程序,更新文件。
  3. 如果其他程序需要有最新的YAML文档,您可以在每次更新时写出YAML,也可以使用某种机制通知P需要编写YAML文档。我使用了SIGINT处理和基于零的通信。

如果您使用真正的数据库,并且对于所有具有相同字段的简单记录表,这可能是一个更好的选择。然而,一旦事情变得更加复杂:每个记录的不同字段、复杂的和可能的递归数据,那么许多(SQL)数据库就会成为一个额外的问题,而不是帮助解决您试图解决的问题。

ruamel.yaml.base (免责声明:我是该包的作者)为您做项目2),其他两项也很容易实现。唯一棘手的事情是,YAMLBase通常期望在根级别对新文件进行映射/dict,所以当文件还不存在时,需要进行一些强制。

在你做pip install ruamel.yaml.base之后

代码语言:javascript
复制
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()

这意味着:

代码语言:javascript
复制
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的一些信息,说明包中正在发生什么。

如果您有很多记录,那么您可能希望将Contacts中的Contacts更改为self.fast_data,然后使用基于C的加载程序加载YAML,代价是无法在输入的YAML中保留(手动添加)注释等。(在这两种情况下,都使用"safe_load“)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52352421

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档