Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Python 程序配置文件管理的最佳工程实践

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

作者头像
初代庄主
发布于 2023-04-20 11:08:24
发布于 2023-04-20 11:08:24
1.1K00
代码可运行
举报
文章被收录于专栏:初代庄主初代庄主
运行总次数:0
代码可运行

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

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

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


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

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
"""实例配置管理
"""

from dataclasses import dataclass


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

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
In [6]: a = Config()

In [7]: b = Config()

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

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

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


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

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
"""实例配置管理
"""

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 就是这么的简单,几行代码就搞定了。但是还是要测试一下顺带引导出下一个需求。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 ,现在就可以写读取配置文件并更新配置对象值的代码了。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
"""实例配置管理
"""

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))

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
cat /tmp/config.json 
{
  "name": "trump",
  "port": 8848
}

下面的测试一下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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),我们可以在这里指定回调函数,这个时候保存配置文件再适合不过。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
"""实例配置管理
"""

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)

验证一下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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()
WARNING:root:save configs to '/tmp/config.json' 

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
cat /tmp/config.json 
{
    "name": "hello-world",
    "port": 8848
}

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


本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-03-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 初代庄主 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
[Python小脚本]Yaml配置文件动态加载
这里需要说明的是,常说的动态加载配置,一般基于观察者设计模式实现的发布/订阅系统,一般有两种模式,分别是推(Push)模式和拉(Pull)模式。
山河已无恙
2023/03/02
1.3K0
python之configparser配置文件解析器
configparser 模块是 Python 标准库中用于处理配置文件的模块,它可以读取、写入和修改配置文件。配置文件通常用于存储程序的配置选项、参数或者其他需要持久化的配置信息。下面简单写一下 configparser 模块的使用示例
不止于python
2023/09/05
1770
python之configparser配置文件解析器
Python: 类封装技巧, 以 Log 类为例
在软件开发中,日志记录是一个非常重要的部分。良好的日志记录可以帮助开发者在调试和维护代码时更好地理解程序的行为。本文将通过一个具体的日志记录类 MyLog,介绍如何在 Python 中使用类封装技巧来实现一个功能强大的日志记录系统。
运维开发王义杰
2024/06/11
1480
Python: 类封装技巧, 以 Log 类为例
Python日志和配置库
日志和配置是应用不可缺少的部分,本文用于介绍dynaconf和loguru的简要用法。
雪飞鸿
2023/07/09
5060
Python日志和配置库
从新手到专家:如何用Python编写配置文件
设计软件时,我们通常要花费很多精力编写高质量代码。但这还不够,一个好的软件还应关注它的生态系统,例如测试,部署,网络等,这其中最重要的一方面就是配置管理。
程序员小强
2021/04/14
7.1K0
友好的 Python:面向对象接口
很久没更新了,写这篇文章是因为受了高天直播 Code Review的启发,深刻感觉到 Python 的灵活和强大,导致了实现同样的功能不同的人会写出完全不一样的代码。Python 语法糖有很多,如何把握「甜度」?过犹不及,我就本人的口味来细说一下。
岂不美哉Frost
2023/10/19
2320
友好的 Python:面向对象接口
这几个高级技巧,让 Python 类如虎添翼
实例方法是以 self 作为第一个参数定义的方法,它将类的实例作为隐式输入,允许用户与类的属性进行交互。实例方法功能强大,因为它们可以访问和修改实例中的数据和配置,从而执行复杂的计算和实现复杂的逻辑,并具有很高的可读性和可维护性。
数据STUDIO
2024/05/23
1150
这几个高级技巧,让 Python 类如虎添翼
一文带你读懂Micro框架如何读取配置文件
我们在写程序的时候,一个无法避免的步骤就是配置文件的编写,有了配置文件,就要有相应的加载机制,比如读取配置文件到实体中,配置文件因为语法简单,具有灵活性,在程序中被广泛的使用,如今流行的有xml,json,yml等类型的配置文件,这一篇我们主要了解在Micro框架中是如何加载我们的配置文件。
陌无崖
2019/08/16
1.1K0
AutoLine源码分析之配置管理
AutoLine开源平台是一个开源自动化测试解决方案,基于RobotFramework进行二次开发,支持RobotFramework几乎所有的库。
苦叶子
2018/07/25
3800
AutoLine源码分析之配置管理
Go:使用Viper和YAML管理配置文件
在软件开发中,配置管理是一项基本但至关重要的任务,它涉及到如何有效地管理应用程序的配置变量,例如数据库连接信息、外部服务的API密钥等。一个好的配置管理工具不仅可以帮助开发人员更容易地管理这些配置,还可以提高应用程序的安全性和灵活性。今天,我们将探讨如何使用Viper库配合YAML配置文件来实现高效的配置管理。
运维开发王义杰
2024/04/15
1.3K0
Go:使用Viper和YAML管理配置文件
Go几种读取配置文件的方式
如果只希望绑定特定的,可以使用SetEnvPrefix("global.source", "MYAPP_GLOAL_SOURCE"),注意这个函数不会自动加上MYAPP的前缀.
fliter
2023/09/07
7810
Go几种读取配置文件的方式
最全总结 | 聊聊 Python 数据处理全家桶(配置篇)
常用配件文件的处理方式,包含:JSON、ini / config、YAML、XML 等
AirPython
2020/10/23
1K0
最全总结 | 聊聊 Python 数据处理全家桶(配置篇)
springboot配置文件整理
# 内嵌tomcat端口号 server.port=8081 server.servlet.context-path=/ # 数据库配置 spring.datasource.driver-class
shaoshaossm
2022/12/26
3890
Viper,一个Go语言配置管理神器!
文章链接:https://cloud.tencent.com/developer/article/2466037
南山竹
2024/11/16
910
Viper,一个Go语言配置管理神器!
YAML配置管理最佳实践
管理接口框架配置是构建强大的接口测试框架的关键一环。良好的配置管理可以提高测试效率、可维护性和可扩展性。在本文中,我们将重点介绍使用YAML(YAML Ain’t Markup Language)来管理接口框架配置的最佳实践,并通过实例演示其用法。
FunTester
2023/10/24
4540
YAML配置管理最佳实践
python操作cfg配置文件
*.cfg文件一般是程序运行的配置文件,python为读写常见配置文件提供了一个ConfigParser模块,所以在python中解析配置文件相当简单,下面就举例说明一下具体的操作方法。
py3study
2020/01/07
6.5K0
Django-admin管理工具
admin组件使用 Django 提供了基于 web 的管理工具。 Django 自动管理工具是 django.contrib 的一部分。你可以在项目的 settings.py 中的 INSTALLED_APPS 看到它: # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'djan
新人小试
2018/06/13
2.1K0
Golang中四种文件配置方式实现
在实际的开发过程中,我们必然会用到MySQL、Redis等这样的服务。为了实现系统的配置化,我们会把一些配置信息单独放在一些文件中,使用到的地方直接读取配置文件即可。
兔云小新LM
2021/12/03
1.3K0
Golang中四种文件配置方式实现
5.Go语言之配置文件读取学习记录
描述: 作为开发者相信对应用程序的配置文件并不陌生吧,例如 Java Spring Boot 里的 class 目录中程序配置,当然go语言相关项目也是可以根据配置文件的格式内容进行读取的,常规的配置文件格式有 json、ini、yaml (个人推荐)、properties 等,我们可以使用其为程序配置一些初始化的可变参数,例如 数据库字符串链接以及认证密码等等。
全栈工程师修炼指南
2023/05/03
1.2K0
Django之admin的使用和源码剖析
admin组件使用 Django 提供了基于 web 的管理工具。 Django 自动管理工具是 django.contrib 的一部分。你可以在项目的 settings.py 中的 INSTALLED_APPS 看到它: # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'djan
人生不如戏
2018/05/30
2.2K0
相关推荐
[Python小脚本]Yaml配置文件动态加载
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验