简介开发人员每天都要处理一些大型复杂的项目,配置文件会帮助我们节省很多时间。在处理配置文件的过程中,本身不需要改动源代码,只需要调整配置文件访问不同的API接口,更新基本的URL信息或者其他的东西。虽然在软件中支持配置文件的方式有很多种,包括JSON、YAML、纯文本文件,但本文旨在向大家介绍Python标准库中的configparser模块。注意:本文基于Python3.9.0(CPython)。源代码可以在GitHub上找到。(https://github.com/DahlitzFlorian/how-to-work-with-config-files-in-python-article-snippets)文件结构在写代码之前,我们先看看实际的配置文件结构。[DEFAULT]admin_page=nolanding_page=yesmoderator_page=no#looksgoodhere[moderator]moderator_page=yes[admin]admin_page=yesmoderator_page=yes在当前示例中,我们有一个名为config.ini的配置文件。它由三个部分组成,每个部分都包含一个用方括号括起来的标题和一个键值对列表。moderator和admin模块只是键值对的集合,但是DEFAULT模块(第一个模块)有些特殊。如果其他模块之一未提供键的值,它将包含默认值。因此,如果您尝试访问另一个模块中的值,但键不存在,解析器将从默认部分(如果存在)返回值,而不是引发KeyError。在这个例子中,我们通过这个配置文件来管理用户的页面访问。因此default部分代表普通用户的权限,而moderator和admin模块分别包含coordinator和administrator的权限。访问文件的内容ConfigParser对象是主要的配置解析器和configparser模块的主要对象。您可以使用映射协议实现自己的配置解析器,让我们继续本文中的ConfigParser。虽然ConfigParser接受很多参数,但我们将使用本文的默认值。让我们在工作目录中创建一个名为parser_playground.py的新文件。首先,我们从configparser模块导入ConfigParser类并创建该类的一个实例。#parser_playground.pyfromconfigparserimportConfigParserconfig=ConfigParser()我们的配置对象不包含任何信息,要改变这个我们需要先读取config.ini文件。这可以通过调用ConfigParser实例(此处为config)的read()方法来完成。#previouscodeinparser_playground.pyconfig.read("config.ini")阅读配置文件后,我们就可以开始探索如何访问其中存储的信息了。首先,我们要列出所有可用的部分。这可以通过使用ConfigParser的sections()方法来实现:#previouscodeinparser_playground.pyprint(f"Sections:{config.sections()}")#Sections:['moderator','admin']此外,我们可以使用parserhas_section()方法检查模块是否存在:#previouscodeinparser_playground.pyprint(f'Doesasectioncalled"admin"exist:{config.has_section("admin")}')#Trueprint(f'Doesasectioncalled"user"exist:{config.has_section("user")}')#Falseprint(f'Doesasectioncalled"DEFAULT"exist:{config.has_section("DEFAULT")}')#False注意:调用sections()方法时,默认模块都不存在已列出,并且未通过has_section()方法确认。接下来,我们要访问各个值。但在使用其标识符访问特定值之前,我们可以使用options()方法列出模块的所有可用选项,提供模块名称作为参数:#Previouscodeinparser_playground.pyprint(f'Options:{config.options("admin")}')#Options:['admin_page','moderator_page','landing_page']此外,我们可以使用has_option()方法检查给定部分是否包含选项:#Previouscodeinparser_playground.pyprint(f'“admin”部分中的“admin_page”:{config.has_option(“admin”,“admin_page”)}')要访问模块的值,请使用解析器的get()方法并提供部分名称和选项名称。如果存在,这些值将始终是字符串。如果需要其他格式的文件,请考虑使用相应的getboolean()、getint()和getfloat()方法。他们将尝试将字符串解析为所需的数据类型。在本节的总结中有一个概念需要提及,就是映射协议接入。这个通用名称意味着可以像字典一样访问这些值。也就是说,我们可以使用类似config["section"]["option"]的东西来访问一个值,甚至检查模块中是否存在一个选项:#Previouscodeinparser_playground.pyprint("admin_page"inconfig["admin"])#Trueprint(config["admin"]["admin_page"])#yes如何修改信息接下来我们看看如何添加或更改信息,并将其写回配置文件。同样,我们从模块开始。要添加模块,我们可以使用ConfigParser的add_section()方法。它接受模块名称作为字符串并将相应的模块添加到解析器。提供不同的数据类型会导致TypeError。如果模块已经存在,则引发DuplicateSectionError。尝试将模块命名为默认值会导致ValueError。#Previouscodeinparser_playground.pyconfig.add_section("unknown")print(f'Sections:{config.sections()}')#Sections:['moderator','admin','unknown']要删除模块,只需使用remove_section()方法。#Previouscodeinparser_playground.pyconfig.remove_section("unknown")print(f'Sections:{config.sections()}')#Sections:['moderator','admin']Python的ConfigParser对象提供了类似的操作选项的方法。例如,调用set()方法不仅会向模块添加新选项,还会更新现有选项。同样,如果您想完全删除一个选项,请使用解析器的remove_option()方法。#Previouscodeinparser_playground.pyconfig.set("admin","admin_page","false")config.remove_option("admin","moderator_page")print(f'Optionsin"admin"部分:{config.items("admin")}')处理完配置后,我们可以像这样将其写回相同或不同的文件:#Previouscodeinparser_playground.pywithopen("config1.ini","w")asf:config.write(f)但同样非常重要的是,让我们看看是什么让ConfigParser优于Python的json模块:插值。插值意味着可以调用某些get()方法在返回值之前对其进行预处理。configparser模块提供了两个插值类:BasicInterpolation和ExtendedInterpolation。第一个只允许在配置文件中重复使用同一模块中的选项,并且它的语句不如后一个类的语句漂亮。这就是我们只使用ExtendedInterpolation类的原因。以下代码片段显示了使用扩展插值语句的配置文件。#interpolation_config.ini[paths]root_dir=/home/floriandownloads_dir=${root_dir}/Downloads[destinations]app_dir=${paths:downloads_dir}/application/python实际上,第一个模块定义了根目录的路径。此路径用作第二个选项的前缀,即下载目录的路径。在第二个模块中,我们有一个选项app_dir,它重用了pahts模块中下载目录的定义。为了掌握这一点,我们让ConfigParser在实例化解析器时使用ExtendedInterpolation作为插值类型:destinations模块选项的值,你会得到一个内插字符串。#Previouscodeininterpolation.pyprint(config.get("destinations","app_dir"))$pythoninterpolation.py/home/florian/Downloads/application/python总结如何操作和扩展它们。此外,您还了解了configparser的插值函数以及如何根据需要使用它们。
