上一篇《用configparser模块读写ini配置文件》,主要聚焦在读写配置文件的基本方法。本文介绍configparser模块的一些高级用法。
首先,我觉得要清楚一个概念,配置文件不一定都有ini后缀,这只是Win系统的习惯。Win系统的文件,一般都通过后缀名来区分文件类型。Linux系统下,文件有没有后缀是无所谓的。只要是文本文件,都可以用作配置文件。
更多读取配置的方式
configparser模块除了使用read函数读取配置文件以外,还可以从字符串,dict对象读取配置。下面是示例代码:
>>> configstr = """
... [Server]
... addr = 1.2.3.4
... domain = py.maixj.net
... [MISC]
... port = 12345
... log = on
... """
>>> config = configparser.ConfigParser()
>>> config.read_string(configstr)
>>> config.sections()
['Server', 'MISC']
下面是从dict对象读取配置的示例代码:
>>> config_dict = {'Server':{'addr' : '1.2.3.4',
... 'domain' : 'py.maixj.net'},
... 'MISC' : {'port' : 12345,
... 'log' : 'on'}}
>>> config = configparser.ConfigParser()
>>> config.read_dict(config_dict)
>>> config.sections()
['Server', 'MISC']
>>> config['MISC'].getboolean('log')
True
建议保持配置项小写
在使用configparser模块时,始终要意识到这个细节。为了保持简单,我们都使用小写即可,除了section的名称。
下面的代码,判断log是否在MISC这section内,不管log这三个字母如何大小写变化,结果都是True:
>>> 'log' in config['MISC']
True
>>> 'LOG' in config['MISC']
True
>>> 'loG' in config['MISC']
True
DEFAULT区域无法删除
我们先看一下clear函数的用法:
>>> config_str = """
... [DEFAULT]
... name = maixj
... gender = male
... [Server]
... addr = 1.2.3.4
... domain = py.maixj.net
... [MISC]
... log = off
... """
>>> config = configparser.ConfigParser()
>>> config.read_string(config_str)
>>> config['MISC'].getboolean('log')
False
>>> config['MISC'].clear()
>>> config['MISC'].getboolean('log') is None
True
在section下调用clear函数,就是讲section下所有的配置项清除。如果在整个config模块下调用clear,就是将所有的section清除,除了DEFAULT区域:
>>> config.sections()
['Server', 'MISC']
>>> config['Server']['domain']
'py.maixj.net'
>>> config['Server'].clear()
>>> config['Server'].get('addr') is None
True
>>> config.clear()
>>> config.sections()
[]
>>> config['DEFAULT']['name']
'maixj'
>>> config['DEFAULT']['gender']
'male'
>>> config.default_section
'DEFAULT'
>>> config.defaults()
OrderedDict([('name', 'maixj'), ('gender', 'male')])
sections函数看不到任何区域了,但是DEFAULT区域还在。
遍历某区域的所有配置
除了上一篇介绍的方法,这里再给出另一种遍历的方法,使用items函数(dict对象也有这个函数):
>>> config_str = """
... [Server]
... addr = 1.2.3.4
... domain = py.maixj.net
... log = yes
... cache = yes
... """
>>> config = configparser.ConfigParser()
>>> config.read_string(config_str)
>>> for k,v in config['Server'].items():
... print(k,'=',v)
...
addr = 1.2.3.4
domain = py.maixj.net
log = yes
cache = yes
配置值的插入替换(interpolation)
之前所有的代码使用中,创建config对象的方法都是一样的,这种方式支持基本的配置值插入替换(basic interpolation):
>>> config_str = """
... [Path]
... home = /home/xinlin
... video = %(home)s/Video
... movie = %(video)s/Movie
... """
>>> config = configparser.ConfigParser()
>>> config.read_string(config_str)
>>> config['Path']['home']
'/home/xinlin'
>>> config['Path']['video']
'/home/xinlin/Video'
>>> config['Path']['movie']
'/home/xinlin/Video/Movie'
Basic Initerpolation的意思是,这种插入替换只能出现在相同的区域,不能跨区,正如上面的代码,home与video,audio在同一个Path区域。插入替换home值的方式是:%(home)s。
还有个细节,上面的代码,实现的是多层插入替换,movie的值来之video,video的值又来自home。我看configparser模块的源码,貌似支持10层这样的插入替换。
configparser模块还支持扩展的配置值插入替换方式,Extended Interpolation。扩展的方式,就是在替换的时候,可以跨区,而且语法上也有区别。Basic和Extended两种方式的语法不兼容。下面是Extended Interpolation的代码示例:
>>> config_str = """
... [Home]
... home = /home/xinlin
... [Lib]
... lib = ${Home:home}/Lib
... gcc_lib = ${lib}/gcc
... [DEFAULT]
... binpath = /usr/bin
... [Path]
... path = ${binpath}/secret
... """
>>> from configparser import ConfigParser, ExtendedInterpolation
>>> config = ConfigParser(interpolation=ExtendedInterpolation())
>>> config.read_string(config_str)
>>> config['Lib']['lib']
'/home/xinlin/Lib'
>>> config['Lib']['gcc_lib']
'/home/xinlin/Lib/gcc'
>>> config['Path']['path']
'/usr/bin/secret'
注意config对象的创建方式变了,多了一个参数。Extended Interpolation方式的插入替换语法是 ${section:option},如果此语法中没有section,要么在同section下找,要么在DEFAULT区域下找。
有了插入替换,使用configparser可以创建出满足各种需求场景的配置文件。
允许配置没有值(allow_no_value)
如果某个配置项,后面有=号,或者:号,表示值为空字符串,并不是没有值。不写=号,或者:号,才是没有值。没有值,就是None,就像没有此配置项一样。请看下面的示例代码:
>>> config_str = """
... [ABC]
... a = 1
... b
... c = 3
... """
>>> config = configparser.ConfigParser(allow_no_value=True)
>>> config.read_string(config_str)
>>> config['ABC']['b']
>>> config['ABC']['b'] is None
True
-- EOF --