很多命令行工具在使用时,都会用到配置文件,比如:版本控制工具 Git 会读取 ~/.gitconfig 进行配置;MySQL 数据库的客户端默认使用 /etc/mysql/my.cnf 中的配置;Pip 工具的配置文件位于 ~/.pip/pip.conf。使用配置文件的好处在于,配置完成后不需要每次使用都指定一次参数,因此配置文件的应用非常广泛,也是我们编写命令行工具时常会用到的。
下面是一个典型的 ini 格式的配置文件,该章节包含一到多个 section ,每个 section 下面可以包含一到多个 option :

在 Python 语言中,我们使用 configparser (Python2 中命名为 ConfigParser)库来解析、读取和修改配置文件。
读取配置文件
解析配置文件时,首先需要创建一个 ConfigParser 对象,其中有个常用的参数 allow_no_value ,默认取值为 False ,表示不允许配置文件中出现只有选项没有值的情况。此处我们在实例化 ConfigParser 时,需要指定 allow_no_value 为 True ,因为我们的配置文件包含一个名为 skip-external-locking 的选项,该选项只有选项名称没有选项值。
下面我们来解析上述的配置文件:
>> import configparser
>> cf = configparser.ConfigParser(allow_no_value=True)
>> cf
<configparser.ConfigParser at 0x1b80bed6610>
>> cf.read('my.cnf')
['my.cnf']
至此,cf.read 方法已经完成了配置文件的读取;此外,也可以使用 cf.readfp 从一个已经打开的文件中读取配置内容。
解析配置文件
ConfigParser 类提供了以下方法,用以解析配置文件内容、判断配置项,总结如下:
| 方法 | 说明 |
|---|---|
| sections | 返回包含所有章节的列表。 |
| has_section | 判断某个章节是否存在。 |
| items | 以元组的形式返回所有选项。 |
| options | 以列表形式返回某个章节下的所有选项。 |
| has_option | 判断某个选项是否存在。 |
| get / getboolean / getint / getfloat | 获取选项的值。 |
下面,我们继续以 my.cnf 为例,说明各个方法的使用:
>> cf.sections()
['client', 'mysqld']
>> cf.has_section('client')
True
>> cf.options('client')
['port', 'user', 'password', 'host']
>> cf.has_option('client', 'port')
True
>> cf.get('client', 'host')
'172.0.0.1'
>> cf.getint('client', 'port')
3306
>> cf.items('mysqld')
[('basedir', 'usr'),
('datadir', 'varlibmysql'),
('tmpdir', 'tmp'),
('skip-external-locking', '')]
注:
get方法默认以字符串的形式返回选项值。
修改配置文件
ConfigParser 提供了如下的方法,供我们修改配置文件时使用:
| 方法 | 说明 |
|---|---|
| remove_section | 删除一个章节。 |
| add_section | 添加一个章节。 |
| remove_option | 删除一个选项。 |
| set | 添加一个选项。 |
| write | 将 ConfigParser 中的数据保存到文件中。 |
通常在修改配置文件之前,我们需要先将配置文件做一个备份,此处我们不妨直接使用 ConfigParser 的 write 方法来进行备份:
>> cf.write(open('my.cnf.back', 'wt', encoding='utf-8'))

下面,我们来对 ConfigParser 对象的内容进行修改:
>> cf.remove_section('client')
True
>> cf.add_section('mysql')
>> cf.set('mysql', 'host', '172.0.0.1')
>> cf.set('mysql', 'port', '3306')
使用 write 方法使修改生效:
>> cf.write(open('my.cnf', 'wt', encoding='utf-8'))
