有时,一个程序需要足够多的参数,把它们全部作为命令行参数或环境变量是不愉快的,也是不可行的。在这些情况下,你会想使用一个配置文件。
有几种流行的配置文件格式。其中有古老的 (虽然偶尔定义不足)INI 格式,流行的但有时难以手写的JSON 格式,广泛的但偶尔在细节上令人惊讶的YAML 格式,以及最新增加的TOML ,许多人还没有听说。
你的首要任务是选择一种格式,然后记录这一选择。在这个简单的部分完成后,现在是解析配置的时候了。
有时,有一个与配置中的 "抽象 "数据相对应的类是个好主意。因为这段代码不会对配置做任何事情,这是展示解析逻辑的最简单方法。
想象一下一个文件处理器的配置:它包括一个输入目录,一个输出目录,以及要接收哪些文件。
配置类的抽象定义可能看起来是这样的。
from __future__ import annotations
import attr
@attr.frozen
class Configuration:
@attr.frozen
class Files:
input_dir: str
output_dir: str
files: Files
@attr.frozen
class Parameters:
patterns: List[str]
parameters: Parameters
为了使特定格式的代码更简单,你还将写一个函数来解析这个类的字典。注意,这假设配置将使用破折号,而不是下划线。这种差异并不罕见。
def configuration_from_dict(details):
files = Configuration.Files(
input_dir=details["files"]["input-dir"],
output_dir=details["files"]["output-dir"],
)
parameters = Configuration.Paraneters(
patterns=details["parameters"]["patterns"]
)
return Configuration(
files=files,
parameters=parameters,
)
JSON
JSON(JavaScript Object Notation)是一种类似JavaScript的格式。
下面是一个JSON格式的配置例子。
json_config = """
{
"files": {
"input-dir": "inputs",
"output-dir": "outputs"
},
"parameters": {
"patterns": [
"*.txt",
"*.md"
]
}
}
"""
解析逻辑使用json 模块将 JSON 解析为 Python 的内置数据结构 (字典、列表、字符串),然后从字典中创建类。
import json
def configuration_from_json(data):
parsed = json.loads(data)
return configuration_from_dict(parsed)
INI
INI格式,最初在Windows上流行,成为事实上的配置标准。
这里是作为 INI 的相同配置。
ini_config="""
[files]
input-dir = inputs
output-dir = outputs
[parameters]
patterns = ['*.txt', '*.md']
"""
Python 可以使用内置的configparser 模块对其进行解析。解析器表现为一个dict-样的对象,所以它可以直接传递给configuration_from_dict 。
import configparser
def configuration_from_ini(data):
parser = configparser.ConfigParser()
parser.read_string(data)
return configuration_from_dict(parser)
YAML
YAML (Yet Another Markup Language) 是JSON的一个扩展,旨在更容易手工编写。它实现了这一点,部分原因是它有一个很长的规范。
下面是YAML中的相同配置。
yaml_config = """
files:
input-dir: inputs
output-dir: outputs
parameters:
patterns:
- '*.txt'
- '*.md'
"""
为了让Python解析这个,你需要安装一个第三方模块。最流行的是PyYAML (pip install pyyaml)。YAML 解析器也会返回内置的 Python 数据类型,可以传递给configuration_from_dict 。然而,YAML解析器期望的是一个流,所以你需要将字符串转换为一个流。
import io
import yaml
def configuration_from_yaml(data):
fp = io.StringIO(data)
parsed = yaml.safe_load(fp)
return configuration_from_dict(parsed)
TOML
TOML(Tom's Own Markup Language)被设计成YAML的轻量级替代品。它的规范更短,而且在一些地方已经很流行了(例如,Rust的包管理器Cargo就使用它来进行包配置)。
下面是与TOML相同的配置。
toml_config = """
[files]
input-dir = "inputs"
output-dir = "outputs"
[parameters]
patterns = [ "*.txt", "*.md",]
"""
为了解析TOML,你需要安装一个第三方的包。最流行的一个叫,简单地说,toml 。像YAML和JSON一样,它返回基本的Python数据类型。
import toml
def configuration_from_toml(data):
parsed = toml.loads(data)
return configuration_from_dict(parsed)
总结
选择一种配置格式是一种微妙的权衡。然而,一旦你做出决定,Python 可以用几行代码来解析大多数流行的格式。