0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Python程序配置文件管理的最佳工程实践

马哥Linux运维 来源:马哥Linux运维 2023-05-04 10:00 次阅读

背景

最近在结合 Python-3.12.0a6 版本开发一个多线程架构的后台服务;服务启动时会读取配置文件,并且要求所有线程共享同一份配置。

服务本身直接通过 http 接口来动态调整配置项的值,还要做到服务退出之后持久化配置项到配置文件。

一开始以为这个用 Python 写也会要用几百行,最后发现完成核心功能就只需要不到 50 行,Python 牛逼!!!


需求一:支持简单的配置项

假设我们目前只支持 name 和 port 两个配置项,多支持几个不难,只是不方便演示。

"""实例配置管理
"""


from dataclasses import dataclass




@dataclass
class Config(object):
    name:str= "mysql"
    port:int = 3306

看起来是没问题了,下面可以试用一下,也顺带引导出第二个需求。

In [6]: a = Config()


In [7]: b = Config()


In [8]: id(a)
Out[8]: 4407850896


In [9]: id(b)
Out[9]: 4407852496

可以看到两个配置对象的 ID 值不一样。由于配置文件只有一个,我们希望配置对象也只有一个。


需求二:配置对象全局唯一

交代一个背景,解释器在做 import 的时候是单一线程在跑的。有了这个前提我们可以少写一些加锁的代码,能少写一行算一行吧。

"""实例配置管理
"""


from dataclasses import dataclass




@dataclass
class Config(object):
    name:str= "mysql"
    port:int = 3306


    _instance = None


    # 单例模式
    def __new__(cls, *args, **kw):
        if cls._instance is None:
            cls._instance = object.__new__(cls, *args, **kw)
        return cls._instance

用 Python 就是这么的简单,几行代码就搞定了。但是还是要测试一下顺带引导出下一个需求。

In [4]: a = Config()


In [5]: b = Config()


In [6]: id(a)
Out[6]: 4414751568


In [7]: id(b)
Out[7]: 4414751568

现在配置对象已经是单例了,但还有一个问题,它的每个配置项的值都是默认值,我们当然是希望它在创建对象的时候是使用配置文件中的值啦。下面看需求三怎么实现。


需求三:根据配置文件构造配置对象

假设我们的配置文件被 “持久化” 到了 /tmp/config.json ,现在就可以写读取配置文件并更新配置对象值的代码了。

"""实例配置管理
"""


import json
import logging
from pathlib import Path
from dataclasses import dataclass




@dataclass
class Config(object):
    name:str= "mysql"
    port:int = 3306


    _instance = None


    # 单例模式
    def __new__(cls, *args, **kw):
        if cls._instance is None:
            cls._instance = object.__new__(cls, *args, **kw)
        return cls._instance


    # 读取配置文件
    def __post_init__(self):
        """如果配置文件存在就用配置文件中的值,覆盖默认值。在这个过程中如果遇到异常就保持默认值
        """
        if (config_file:=Path("/tmp/config.json")) and config_file.exists():
            try:
                with open(config_file) as f:
                    json_data = json.loads(f.read())
                    self.__dict__.update(json_data)
            except Exception as err:
                pass
        else:
            logging.warn("config file '{}' not exists. well using defautl values .".format(config_file))

假设我们的配置文件内容是这样的。

cat /tmp/config.json 
{
  "name": "trump",
  "port": 8848
}

下面的测试一下

In [2]: a = Config()


In [3]: a
Out[3]: Config(name='trump', port=8848)


In [4]: b = Config()


In [5]: b
Out[5]: Config(name='trump', port=8848)


In [6]: a == b
Out[6]: True

可以看到 name 和 port 已经没有使用默认的 "mysql" 和 3306 了,而是使用了配置文件中的值。

到这里我们只剩下最后一个需求,就是在程序退出的时候,把配置对象的值更新回配置文件。这个就看需求四怎么写。


需求四:程序退出前自动持久化配置对象到配置文件

解释器在退出前有个钩子(atexit),我们可以在这里指定回调函数,这个时候保存配置文件再适合不过。

"""实例配置管理
"""


import json
import atexit
import logging
from pathlib import Path
from dataclasses import dataclass, asdict




@dataclass
class Config(object):
    name:str= "mysql"
    port:int = 3306


    _instance = None


    # 单例模式
    def __new__(cls, *args, **kw):
        if cls._instance is None:
            cls._instance = object.__new__(cls, *args, **kw)
        return cls._instance


    # 读取配置文件
    def __post_init__(self):
        """如果配置文件存在就用配置文件中的值,覆盖默认值;在这个过程中如果遇到异常就保持默认值。程序退出时持久到到配置到文件。
        """
        if (config_file:=Path("/tmp/config.json")) and config_file.exists():
            try:
                with open(config_file) as f:
                    json_data = json.loads(f.read())
                    self.__dict__.update(json_data)
            except Exception as err:
                pass
        else:
            logging.warn("config file '{}' not exists. well using defautl values .".format(config_file))


        # 程序退出时保存配置到配置文件 /tmp/config.json
        def sync_to_disk():
"""
            """
            json_str = json.dumps(asdict(self), indent=4)
            with open(config_file, 'w') as f:
                logging.warning("save configs to '{}' ".format(config_file))
                f.write(json_str) 


        atexit.register(sync_to_disk)

验证一下

In [1]: from appconfig import Config


In [2]: a = Config()


In [3]: a.name
Out[3]: 'trump'


In [4]: a.name = "hello-world"


In [5]: exit()
WARNINGsave configs to '/tmp/config.json' 

看日志是已经把配置项更新回配置文件了,但是还是 cat 确认一下为好。

cat /tmp/config.json 
{
    "name": "hello-world",
    "port": 8848
}

可以看到确实已经把配置项的值更新到文件了。


审核编辑 :李倩


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 程序
    +关注

    关注

    117

    文章

    3787

    浏览量

    81028
  • 配置
    +关注

    关注

    1

    文章

    188

    浏览量

    18379
  • python
    +关注

    关注

    56

    文章

    4796

    浏览量

    84664

原文标题:Python 程序配置文件管理的最佳工程实践

文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    基于libconfig进行配置文件解析

    本文介绍基于libconfig进行配置文件解析
    的头像 发表于 06-08 10:18 1414次阅读
    基于libconfig进行<b class='flag-5'>配置文件</b>解析

    ICD配置文件的详细介绍和配置内容的详细概述

    配置文件配置文件是利用SCL语言描述变电站设备对象模型后生成的文件,用于在不同厂商的配置工具之间交换配置信息。
    的头像 发表于 06-02 11:16 1.8w次阅读
    ICD<b class='flag-5'>配置文件</b>的详细介绍和<b class='flag-5'>配置</b>内容的详细概述

    Keil的黑色界面配置文件配置方法

    本文档的主要内容详细介绍的是Keil的黑色界面配置文件配置方法。
    发表于 12-03 15:05 26次下载

    Python进行配置文件的教程免费下载

    本文档的主要内容详细介绍的是Python进行配置文件的教程免费下载。
    发表于 09-30 16:41 6次下载
    <b class='flag-5'>Python</b>进行<b class='flag-5'>配置文件</b>的教程免费下载

    AD8283评估板设计和配置文件

    AD8283评估板设计和配置文件
    发表于 05-31 16:04 9次下载
    AD8283评估板设计和<b class='flag-5'>配置文件</b>

    Python 中常见的配置文件写法有哪些

    固定文件我们可以直接写成一个  .py  文件,例如  settings.py  或  config.py ,这样的好处就是能够在同一工程下直接通过  import  来导入当中的部分;但如果我们需要在其他 非
    的头像 发表于 10-20 16:11 2290次阅读
    <b class='flag-5'>Python</b> 中常见的<b class='flag-5'>配置文件</b>写法有哪些

    labview读写配置文件实例分享

    labview读写配置文件实例分享
    发表于 11-01 16:05 45次下载

    SpringBoot配置文件application

    Map配置 YML配置文件: sys-num: mymap: "{'a':'aaa','b':'bbb'}" 方法内: public class learnMap { @Value
    的头像 发表于 01-13 15:28 650次阅读

    KT142C语音芯片配置文件总是不起作用?配置文件的问题集中归纳

    KT142C语音芯片配置文件总是不起作用?配置文件的问题集中归纳
    的头像 发表于 10-20 15:04 579次阅读
    KT142C语音芯片<b class='flag-5'>配置文件</b>总是不起作用?<b class='flag-5'>配置文件</b>的问题集中归纳

    linux修改网卡ip配置文件

    Linux是一种开源的操作系统,因此,它给用户提供了很高的自由度,可以根据个人需要进行各种定制和配置。其中,修改网络接口配置文件是常见的操作,可以通过修改网卡ip配置文件来设置网络接口的IP地址
    的头像 发表于 11-17 10:51 2246次阅读

    springboot的全局配置文件有几种

    Spring Boot是一种快速开发框架,其通过提供配置文件来实现对应用程序配置。全局配置文件在Spring Boot中起着非常重要的作用,可以用于
    的头像 发表于 12-03 15:28 1572次阅读

    springboot的核心配置文件有哪些

    的工作量。 Spring Boot的核心配置文件主要有以下几个: application.properties:Spring Boot应用程序的主要配置文件。它使用Java的键值对格式来定义各种
    的头像 发表于 12-03 15:30 1172次阅读

    zookeeper的核心配置文件是什么

    ,Zookeeper被广泛应用于服务发现、分布式锁、配置管理等场景中。在Zookeeper的设计中,核心配置文件是zoo
    的头像 发表于 12-04 10:33 813次阅读

    php的配置文件是什么

    PHP的配置文件是一种用于配置PHP解释器的文本文件。它包含了一系列的指令和选项,用于影响PHP的行为和性能。通过修改配置文件,可以改变PHP解释器的默认行为,从而满足不同的需求。 在
    的头像 发表于 12-04 15:55 1546次阅读

    oracle配置文件tnsnames怎么配置

    Oracle配置文件tnsnames.ora是一个文本文件,用于定义数据库连接的别名和连接信息。通过配置文件,可以在应用程序中使用别名来连
    的头像 发表于 12-06 10:15 8626次阅读