翼度科技»论坛 编程开发 python 查看内容

[python]常用配置读取方法

7

主题

7

帖子

21

积分

新手上路

Rank: 1

积分
21
前言

常见的应用配置方式有环境变量和配置文件,对于微服务应用,还会从配置中心加载配置,比如nacos、etcd等,有的应用还会把部分配置写在数据库中。此处主要记录从环境变量、.env文件、.ini文件、.yaml文件、.toml文件、.json文件读取配置。
ini文件

ini文件格式一般如下:
  1. [mysql]
  2. type = "mysql"
  3. host = "127.0.0.1"
  4. port = 3306
  5. username = "root"
  6. password = "123456"
  7. dbname = "test"
  8. [redis]
  9. host = "127.0.0.1"
  10. port = 6379
  11. password = "123456"
  12. db = "5"
复制代码
使用python标准库中的configparser可以读取ini文件。
  1. import configparser
  2. import os
  3. def read_ini(filename: str = "conf/app.ini"):
  4.     """
  5.     Read configuration from ini file.
  6.     :param filename: filename of the ini file
  7.     """
  8.     config = configparser.ConfigParser()
  9.     if not os.path.exists(filename):
  10.         raise FileNotFoundError(f"File {filename} not found")
  11.     config.read(filename, encoding="utf-8")
  12.     return config
复制代码
config类型为configparser.ConfigParser,可以使用如下方式读取
  1. config = read_ini("conf/app.ini")
  2. for section in config.sections():
  3.     for k,v in config.items(section):
  4.         print(f"{section}.{k}: {v}")
复制代码
读取输出示例
  1. mysql.type: "mysql"
  2. mysql.host: "127.0.0.1"
  3. mysql.port: 3306
  4. mysql.username: "root"
  5. mysql.password: "123456"
  6. mysql.dbname: "test"
  7. redis.host: "127.0.0.1"
  8. redis.port: 6379
  9. redis.password: "123456"
  10. redis.db: "5"
复制代码
yaml文件

yaml文件内容示例如下:
  1. database:
  2.   mysql:
  3.     host: "127.0.0.1"
  4.     port: 3306
  5.     user: "root"
  6.     password: "123456"
  7.     dbname: "test"
  8.   redis:
  9.     host:
  10.       - "192.168.0.10"
  11.       - "192.168.0.11"
  12.     port: 6379
  13.     password: "123456"
  14.     db: "5"
  15. log:
  16.   directory: "logs"
  17.   level: "debug"
  18.   maxsize: 100
  19.   maxage: 30
  20.   maxbackups: 30
  21.   compress: true
复制代码
读取yaml文件需要安装pyyaml
  1. pip install pyyaml
复制代码
读取yaml文件的示例代码
  1. import yaml
  2. import os
  3. def read_yaml(filename: str = "conf/app.yaml"):
  4.     if not os.path.exists(filename):
  5.         raise FileNotFoundError(f"File {filename} not found")
  6.     with open(filename, "r", encoding="utf-8") as f:
  7.         config = yaml.safe_load(f.read())
  8.         return config
  9.    
  10. if __name__ == "__main__":
  11.     config = read_yaml("conf/app.yaml")
  12.     print(type(config))
  13.     print(config)
复制代码
执行输出,可以看到config是个字典类型,通过key就可以访问到
  1. <class 'dict'>
  2. {'database': {'mysql': {'host': '127.0.0.1', 'port': 3306, 'user': 'root', 'password': '123456', 'dbname': 'test'}, 'redis': {'host': ['192.168.0.10', '192.168.0.11'], 'port': 6379, 'password': '123456', 'db': '5'}}, 'log': {'directory': 'logs', 'level': 'debug', 'maxsize': 100, 'maxage': 30, 'maxbackups': 30, 'compress': True}}
复制代码
toml文件

toml文件比较像yaml,但是不要求缩进格式。如果比较讨厌yaml的缩进问题,那么可以考虑下使用toml。一个简单的toml文件示例如下:
  1. [database]
  2. dbtype = "mysql"
  3. [database.mysql]
  4. host = "127.0.0.1"
  5. port = 3306
  6. user = "root"
  7. password = "123456"
  8. dbname = "test"
  9. [database.redis]
  10. host = ["192.168.0.10", "192.168.0.11"]
  11. port = 6379
  12. password = "123456"
  13. db = "5"
  14. [log]
  15. directory = "logs"
  16. level = "debug"
复制代码
如果python版本高于3.11,其标准库tomllib就可以读取toml文件。读取toml文件的第三方库也有很多,个人一般使用toml
  1. pip install toml
复制代码
读取toml文件的示例代码
  1. import tomllib # python version >= 3.11
  2. import toml
  3. import os
  4. def read_toml_1(filename: str = "conf/app.toml"):
  5.     """
  6.     Read configuration from toml file using tomllib that is python standard package.
  7.     Python version >= 3.11
  8.     """
  9.     if not os.path.exists(filename):
  10.         raise FileNotFoundError(f"File {filename} not found")
  11.     with open(filename, "rb") as f:
  12.         config = tomllib.load(f)
  13.         return config
  14.    
  15. def read_toml_2(filename: str = "conf/app.toml"):
  16.     """
  17.     Read configuration from toml file using toml package.
  18.     """
  19.     if not os.path.exists(filename):
  20.         raise FileNotFoundError(f"File {filename} not found")
  21.    
  22.     with open(filename, "r" ,encoding="utf-8") as f:
  23.         config = toml.load(f)
  24.         return config
  25.    
  26. if __name__ == "__main__":
  27.     config = read_toml_1("conf/app.yaml")
  28.     # config = read_toml_2("conf/app.yaml")
  29.     print(type(config))
  30.     print(config)
复制代码
执行输出,无论使用tomllib或toml,返回的都是dict类型,都可以直接使用key访问。
  1. <class 'dict'>
  2. {'database': {'mysql': {'host': '127.0.0.1', 'port': 3306, 'user': 'root', 'password': '123456', 'dbname': 'test'}, 'redis': {'host': ['192.168.0.10', '192.168.0.11'], 'port': 6379, 'password': '123456', 'db': '5'}}, 'log': {'directory': 'logs', 'level': 'debug', 'maxsize': 100, 'maxage': 30, 'maxbackups': 30, 'compress': True}}
复制代码
json文件

使用标准库json即可读取json文件,json配置文件示例:
  1. {
  2.     "database": {
  3.         "mysql": {
  4.             "host": "127.0.0.1",
  5.             "port": 3306,
  6.             "user": "root",
  7.             "password": "123456",
  8.             "dbname": "test"
  9.         },
  10.         "redis": {
  11.             "host": [
  12.                 "192.168.0.10",
  13.                 "192.168.0.11"
  14.             ],
  15.             "port": 6379,
  16.             "password": "123456",
  17.             "db": "5"
  18.         }
  19.     },
  20.     "log": {
  21.         "level": "debug",
  22.         "dir": "logs"
  23.     }
  24. }
复制代码
解析的示例代码如下
  1. import json
  2. import os
  3. def read_json(filename: str = "conf/app.json") -> dict:
  4.     """
  5.     Read configuration from json file using json package.
  6.     """
  7.     if not os.path.exists(filename):
  8.         raise FileNotFoundError(f"File {filename} not found")
  9.     with open(filename, "r", encoding="utf-8") as f:
  10.         config = json.load(f)
  11.         return config
  12.    
  13. if __name__ == "__main__":
  14.     config = read_json("conf/app.yaml")
  15.     print(type(config))
  16.     print(config)
复制代码
执行输出
  1. <class 'dict'>
  2. {'database': {'mysql': {'host': '127.0.0.1', 'port': 3306, 'user': 'root', 'password': '123456', 'dbname': 'test'}, 'redis': {'host': ['192.168.0.10', '192.168.0.11'], 'port': 6379, 'password': '123456', 'db': '5'}}, 'log': {'level': 'debug', 'dir': 'logs'}}
复制代码
.env文件

从.env文件读取键值对配置,并将它们添加到环境变量中,添加后可以使用os.getenv()获取。
读取.env文件需要安装第三方库
  1. pip install python-dotenv
复制代码
.env文件示例
  1. MYSQL_HOST="127.0.0.1"
  2. MYSQL_PORT=3306
  3. MYSQL_USERNAME="root"
  4. MYSQL_PASSWORD="123456"
  5. MYSQL_DATABASE="test"
复制代码
示例代码
  1. import os
  2. import dotenv
  3. def read_dotenv(filename: str = "conf/.env"):
  4.     if not os.path.exists(filename):
  5.         raise FileNotFoundError(f"File {filename} not found")
  6.     load_dotenv(dotenv_path=filename, encoding="utf-8", override=True)
  7.     config = dict(os.environ)
  8.     return config
  9. if __name__ == "__main__":
  10.     config = read_json("conf/app.yaml")
  11.     for k,v in config.items():
  12.         if k.startswith("MYSQL_"):
  13.             print(f"{k}: {v}")
复制代码
读取环境变量

在标准库os中有以下常用的和环境变量相关的方法,具体可参考官方文档:https://docs.python.org/zh-cn/3/library/os.html


  • os.environ,一个mapping对象,其中键值是代表进程环境的字符串。例如 environ["HOME"]
  1. # example
  2. import os
  3. config = dict(os.environ)
  4. for k,v in config.items():
  5.     print(k,v)
复制代码


  • os.getenv(key, default=None)。如果环境变量 key 存在则将其值作为字符串返回,如果不存在则返回 default。
  • os.putenv(key, value)。设置环境变量,官方文档推荐直接修改os.environ。例如:os.putenv("MYSQL_HOST", "127.0.0.1")
  • os.unsetenv(key)。删除名为 key 的环境变量,官方文档推荐直接修改os.environ。例如:os.unsetenv("MYSQL_HOST")
综合示例

一般来说配置解析相关代码会放到单独的包中,配置文件也会放到单独的目录,这里给个简单的示例。
目录结构如下,conf目录存放配置文件,pkg/config.py用于解析配置,main.py为程序入口。
  1. .
  2. ├── conf
  3. │   ├── app.ini
  4. │   ├── app.json
  5. │   ├── app.toml
  6. │   └── app.yaml
  7. ├── main.py
  8. └── pkg
  9.     ├── config.py
  10.     └── __init__.py
复制代码
pkg/__init__.py文件为空,pkg/config.py内容如下:
  1. import configparser
  2. import os
  3. import yaml
  4. import tomllib
  5. import json
  6. import abc
  7. from dotenv import load_dotenv
  8. class Configer(metaclass=abc.ABCMeta):
  9.     def __init__(self, filename: str):
  10.         self.filename = filename
  11.     @abc.abstractmethod
  12.     def load(self):
  13.         raise NotImplementedError(f"subclass must implement this method")
  14.    
  15.     def file_exists(self):
  16.         if not os.path.exists(self.filename):
  17.             raise FileNotFoundError(f"File {self.filename} not found")
  18. class IniParser(Configer):
  19.     def __init__(self, filename: str):
  20.         super().__init__(filename)
  21.     def load(self):
  22.         super().file_exists()
  23.         config = configparser.ConfigParser()
  24.         config.read(self.filename, encoding="utf-8")
  25.         return config
  26. class YamlParser(Configer):
  27.     def __init__(self, filename: str):
  28.         super().__init__(filename)
  29.     def load(self):
  30.         super().file_exists()
  31.         with open(self.filename, "r", encoding="utf-8") as f:
  32.             config = yaml.safe_load(f.read())
  33.             return config
  34. class TomlParser(Configer):
  35.     def __init__(self, filename: str):
  36.         super().__init__(filename)
  37.     def load(self):
  38.         super().file_exists()
  39.         with open(self.filename, "rb") as f:
  40.             config = tomllib.load(f)
  41.             return config
  42.         
  43. class JsonParser(Configer):
  44.     def __init__(self, cfgtype: str, filename: str = None):
  45.         super().__init__(cfgtype, filename)
  46.     def load(self):
  47.         super().file_exists()
  48.         with open(self.filename, "r", encoding="utf-8") as f:
  49.             config = json.load(f)
  50.             return config
  51.         
  52. class DotenvParser(Configer):
  53.     def __init__(self, filename: str = None):
  54.         super().__init__(filename)
  55.     def load(self):
  56.         super().file_exists()
  57.         load_dotenv(self.filename, override=True)
  58.         config = dict(os.environ)
  59.         return config
复制代码
main.py示例:
  1. from pkg.config import TomlParser
  2. config = TomlParser("conf/app.toml")
  3. print(config.load())
复制代码
执行输出
  1. {'database': {'dbtype': 'mysql', 'mysql': {'host': '127.0.0.1', 'port': 3306, 'user': 'root', 'password': '123456', 'dbname': 'test'}, 'redis': {'host': ['192.168.0.10', '192.168.0.11'], 'port': 6379, 'password': '123456', 'db': '5'}}, 'log': {'directory': 'logs', 'level': 'debug'}}
复制代码
来源:https://www.cnblogs.com/XY-Heruo/p/17953418
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具