Python 中常见的配置文件写法

爱学习的豆包 2021-01-20 18:02:40
Python 配置 配置文件 常见 中常


file

大家好,今天我们来谈一谈 Python 中的配置文件 该怎么写?。

为什么要写配置文件

在开发过程中,我们常常会用到一些固定参数或者是常量。对于这些较为固定且常用到的部分,往往会将其写到一个固定文件中,避免在不同的模块代码中重复出现从而保持核心代码整洁。

这个固定文件我们可以直接写成一个 .py 文件,例如 settings.py 或 config.py,这样的好处就是能够在同一工程下直接通过 import 来导入当中的部分;但如果我们需要在其他非 Python 的平台进行配置文件共享时,写成单个 .py 就不是一个很好的选择。这时我们就应该选择通用的配置文件类型来作为存储这些固定的部分。目前常用且流行的配置文件格式类型主要有 ini、json、toml、yaml、xml 等,这些类型的配置文件我们都可以通过标准库或第三方库来进行解析。

ini

ini 即 Initialize 初始化之意,早期是在 Windows 上配置文件的存储格式。ini 文件的写法通俗易懂,往往比较简单,通常由节(Section)、键(key)和值(value)组成,就像以下形式:

[localdb]
host = 127.0.0.1
user = root
password = 123456
port = 3306
database = mysql

Python 本身内置的 configparser 标准库,我们直接就可以用来对 ini 文件进行解析。如我们将上述内容保存在一个名为 db.ini 的文件中,然后使用 read() 方法来进行解析和读取,最后通过 items() 方法来获取指定节点下的所有键值对。

>>> from configparser import ConfigParser
>>> cfg = ConfigParser()
>>> cfg.read("/Users/Bobot/db.ini")
['/Users/Bobot/db.ini']
>>> cfg.items("localdb")
[('host', '127.0.0.1'), ('user', 'root'), ('password', '123456'), ('port', '3306'), ('database', 'mysql')]

需要注意的是,configparser 默认将值以字符串的形式呈现,所以这也就是为什么我们在 db.ini 文件中没有加引号而是直接将字面量写在上面的原因。

获取到键值对后,我其实直接就将其转换成字典,然后通过解包的方式进行穿参,保持代码简洁:

#!pip install pymysql
import pymysql
from configparser import ConfigParser
cfg = ConfigParser()
cfg.read("/Users/Bobot/db.ini")
db_cfg = dict(cfg.items("localdb"))
con = pymysql.connect(**db_cfg)

json

json 格式可以说是我们常见的一种文件形式了,也是目前在互联网较为流行的一种数据交换格式。除此之外,json 有时也是配置文件的一种。

比如 npm(JavaScript 包管理工具类似 Python 的 pip)、以及微软出品的目前被广泛使用的 VSCode 编辑器,都使用 json 编写配置参数。

和 configparser 一样,Python 也内置了 json 标准库,可以通过 load() 和 loads() 方法来导入文件式和字符串的 json 内容。

{
"localdb":{
"host": "127.0.0.1",
"user": "root",
"password": "123456",
"port": 3306,
"database": "mysql"
}
}

我们将上述内容保存为 db.json 后进行读取和解析,json 库读取 json 文件相对简单容易,而且很容易解析成 Python 的字典对象。

>>> import json
>>> from pprint import pprint
>>> 
>>> with open('/Users/Bobot/db.json') as j:
...  cfg = json.load(j)['localdb']
... 
>>> pprint(cfg)
{'database': 'mysql',
'host': '127.0.0.1',
'password': '123456',
'port': 3306,
'user': 'root'}

使用 json 文件配置的缺点就是语法标准严格限制,为人所诟病之一的就是无法在当中写注释,除非采取 json 类型的其他超集作为替代方案(VSCode 中能写注释的 json 参数配置文件便是代替方案的一种);同时存在嵌套过深的问题,容易导致出错,不宜用来写过长或复杂的参数配置信息。

toml

toml 格式(或 tml 格式)是 Github 联合创始人 Tom Preston-Werner 所提出的一种配置文件格式。根据维基百科的资料,toml 最开始提出时是在 2013年7月份,距今已有七年时间;它在某些方面也与后面要谈到的 yaml 文件有些类似,但如果当你知道 yaml 的规范有几十页(没有错,真的就是几十页……)的时候,可能你真的就不太愿意去写那么复杂的配置文件,toml 格式则倒是个不错的选择。

toml 格式大致如下: file

从这里可以看出 toml 有点类似于前面所讲的 ini 文件。但是它比 ini 扩展了更多的内容。

在样例图片中我们可以看到,除了基本的字符串以外,例如时间戳、布尔值、数组等都进一步支持,而且样式和 Python 的原生写法十分类似。

当然这里不会过多介绍 toml 格式的一些规范说明,有人已经对官方的规范文档进行了翻译,有兴趣的朋友可以直接查阅。

这么契合 Python 方式的配置文件类型已经有开发者造出了相应的「轮子」,目前在 Github 上 Stars 数最多的是则 uiri/toml 的版本,不过该版本仅通过了 v0.5 版本 toml 规范,但在使用上还是蛮简洁的,我们可以通过 pip 命令进行安装

pip install toml

该库的解析方式很简单,也有点类似于 json 库的解析用法,即通过load() 或 loads() 来进行解析;同理转换并导出也是同样类似的用法。

比如我们现在将以下内容写入到 config.toml 中:

[mysql]
host = "127.0.0.1"
user = "root"
port = 3306
database = "test"
[mysql.parameters]
pool_size = 5
charset = "utf8"
[mysql.fields]
pandas_cols = [ "id", "name", "age", "date"]

紧接着我们就可以通过 toml 库中的 load() 方法来进行读取:

>>> import toml
>>> import os
>>> from pprint import pprint
>>> cfg = toml.load(os.path.expanduser("~/Desktop/config.toml"))
>>> pprint(cfg)
{'mysql': {'database': 'test',
'fields': {'pandas_cols': ['id', 'name', 'age', 'date']},
'host': '127.0.0.1',
'parameters': {'charset': 'utf8', 'pool_size': 5},
'port': 3306,
'user': 'root'}}

可以看到 toml 文件被间接地转化成了字典类型,当然这也就是 json 版的写法(将单引号替换成双引号即可),方便我们后续调用或者传参。

yaml

yaml 格式(或 yml 格式)是目前较为流行的一种配置文件,它早在 2001 由一个名为 Clark Evans 的人提出;同时它也是目前被广泛使用的配置文件类型,典型的就是 Docker 容器里的 docker-compose.yml 配置文件,如果经常使用 Docker 进行部署的人对此不会陌生。

yaml 文件的设计从 Python、XML 等地方获取灵感,所以在使用时能很清楚地看到这些部分的影子。

在上一节 toml 内容里我曾提到,yaml 的规范内容可以说是冗长和复杂,足足有80页之多(斗尊强者,恐怖如斯……)。

file

所以感兴趣的朋友可以再自行了解相关用法。

YAML 官方早已经提供了相应的 Python 库进行支持,即 PyYAML;当然也同样需要我们事先进行安装:

pip install pyyaml

同 json 库和 toml 库一样,通过 load() 方法来进行加载。

需要注意的是,使用 load() 方法会存在一定的安全隐患,从思科 Talos 的这份报告中我们可以看到,如果加载了未知或不信任的 yaml 文件,那么有可能会存在被攻击的风险和网络安全隐患,因为它能够直接调用相应的 Python 函数来执行为攻击者所需要的命令,比如说在 yaml 文件中写入这么一段:

# 使用Linux和macOS的朋友不要轻易尝试
!!python/object/apply:os.system ["rm -rf /"]

因此最好是使用 safe_load() 来代替 load() 方法。

这和 Python 内置的 string 标准库中 Template 类的 substitute() 模板方法一样存在着同样的安全隐患,所以使用 safe_substitute() 来替代是一样的道理。

如我们现在将之前的一些配置信息写入 config.yaml 文件中:

mysql:
host: "127.0.0.1"
port: 3306
user: "root"
password: "123456"
database: "test"
parameter:
pool_size: 5
charset: "utf8"
fields:
pandas_cols:
- id
- name
- age
- date

然后我们通过 safe_load() 方法进行解析:

>>> import os
>>> from pprint import pprint
>>> 
>>> with open(os.path.expanduser("~/config.yaml"), "r") as config:
...  cfg = yaml.safe_load(config)
... 
>>> pprint(cfg)
{'mysql': {'database': 'test',
'fields': {'pandas_cols': ['id', 'name', 'age', 'date']},
'host': '127.0.0.1',
'parameter': {'charset': 'utf8', 'pool_size': 5},
'password': '123456',
'port': 3306,
'user': 'root'}}

可以看到最后结果和前面的 toml 库的解析结果基本一致。

结尾

本文列举了一些主流且常见的配置文件类型及其 Python 的读取方法,可能有的读者会发现当中没有 xml 格式类型的内容。对于 xml 配置文件可能与 Java 系语言打交道的朋友遇见得会多一些,但 xml 文件的可读性实在是让人望而生畏;对 xml 文件不了解的朋友可以使用 Chrome 浏览器随便进入一个网站然后按下 F12 进入开发者后查看那密密麻麻的 html 元素便是 .xml 的缩影。

除了这些主流的配置文件类型之外,像一些 .cfg、.properties 等都可以作为配置文件,甚至和开头提到的那样,你单独用一个 .py 文件来书写各类配置信息作为配置文件进行导入都是没问题,只是在跨语言共享时可能会有些障碍。因此本文就不过多介绍,感兴趣的朋友可以进一步自行了解。

在本文里列举的配置文件类型其复杂性由上到下依次增加:ini < json ≈ toml < yaml,它们之间各有优劣,可以根据自己实际的需求和团队协作要求来具体选择。

作者:100gle 来源:Python中文社区

[拿走不谢!Python 3.9 官方中文文档,限时领!] (http://dwz.date/dE6v)

[限时!速领!14张高清Python速查表,效率提升必备!] (http://dwz.date/dE6w)

[GitHub标星3W+,80个Python案例,带你轻松玩转Python学习!] (http://dwz.date/dE64)

版权声明
本文为[爱学习的豆包]所创,转载请带上原文链接,感谢
https://my.oschina.net/u/4630617/blog/4916091

  1. 利用Python爬虫获取招聘网站职位信息
  2. Using Python crawler to obtain job information of recruitment website
  3. Several highly rated Python libraries arrow, jsonpath, psutil and tenacity are recommended
  4. Python装饰器
  5. Python实现LDAP认证
  6. Python decorator
  7. Implementing LDAP authentication with Python
  8. Vscode configures Python development environment!
  9. In Python, how dare you say you can't log module? ️
  10. 我收藏的有关Python的电子书和资料
  11. python 中 lambda的一些tips
  12. python中字典的一些tips
  13. python 用生成器生成斐波那契数列
  14. python脚本转pyc踩了个坑。。。
  15. My collection of e-books and materials about Python
  16. Some tips of lambda in Python
  17. Some tips of dictionary in Python
  18. Using Python generator to generate Fibonacci sequence
  19. The conversion of Python script to PyC stepped on a pit...
  20. Python游戏开发,pygame模块,Python实现扫雷小游戏
  21. Python game development, pyGame module, python implementation of minesweeping games
  22. Python实用工具,email模块,Python实现邮件远程控制自己电脑
  23. Python utility, email module, python realizes mail remote control of its own computer
  24. 毫无头绪的自学Python,你可能连门槛都摸不到!【最佳学习路线】
  25. Python读取二进制文件代码方法解析
  26. Python字典的实现原理
  27. Without a clue, you may not even touch the threshold【 Best learning route]
  28. Parsing method of Python reading binary file code
  29. Implementation principle of Python dictionary
  30. You must know the function of pandas to parse JSON data - JSON_ normalize()
  31. Python实用案例,私人定制,Python自动化生成爱豆专属2021日历
  32. Python practical case, private customization, python automatic generation of Adu exclusive 2021 calendar
  33. 《Python实例》震惊了,用Python这么简单实现了聊天系统的脏话,广告检测
  34. "Python instance" was shocked and realized the dirty words and advertisement detection of the chat system in Python
  35. Convolutional neural network processing sequence for Python deep learning
  36. Python data structure and algorithm (1) -- enum type enum
  37. 超全大厂算法岗百问百答(推荐系统/机器学习/深度学习/C++/Spark/python)
  38. 【Python进阶】你真的明白NumPy中的ndarray吗?
  39. All questions and answers for algorithm posts of super large factories (recommended system / machine learning / deep learning / C + + / spark / Python)
  40. [advanced Python] do you really understand ndarray in numpy?
  41. 【Python进阶】Python进阶专栏栏主自述:不忘初心,砥砺前行
  42. [advanced Python] Python advanced column main readme: never forget the original intention and forge ahead
  43. python垃圾回收和缓存管理
  44. java调用Python程序
  45. java调用Python程序
  46. Python常用函数有哪些?Python基础入门课程
  47. Python garbage collection and cache management
  48. Java calling Python program
  49. Java calling Python program
  50. What functions are commonly used in Python? Introduction to Python Basics
  51. Python basic knowledge
  52. Anaconda5.2 安装 Python 库(MySQLdb)的方法
  53. Python实现对脑电数据情绪分析
  54. Anaconda 5.2 method of installing Python Library (mysqldb)
  55. Python implements emotion analysis of EEG data
  56. Master some advanced usage of Python in 30 seconds, which makes others envy it
  57. python爬取百度图片并对图片做一系列处理
  58. Python crawls Baidu pictures and does a series of processing on them
  59. python链接mysql数据库
  60. Python link MySQL database