前言
将代码中的配置项抽取到配置文件中, 修改配置时不需要涉及到代码修改, 避免面对一堆令人抓狂的 magic number, 极大的方便后期软件的维护.
python 本身提供标准的配置读写模块 configParse(python2,python3 修改为 configparser), 用于读取 INI 格式的配置文件.
- [DEFAULT]
- ServerAliveInterval = 45
- Compression = yes
- [topsecret.server.com]
- Port = 50022
- ForwardX11 = no
除了标准库提供的模块, 通过第三方模块 pyYAML, 可以读写 YAML[1]式的配置文件.
本文介绍 python 通过 configParser 和 pyYAML 读写配置文件的方法.
configParser
Note The ConfigParser module has been renamed to configparser in Python 3. The 2to3 tool will automatically adapt imports when converting your sources to Python 3.
python2 和 python3 中此模块有些许不同, 旧代码可以通过工具进行转换.
目前来说, python2 在项目中仍有使用, 所以以下对在 python2 和 python3 下模块的使用都进行介绍.
python2 - ConfigParser
在 ConfigParser 中提供了三个类:
- RawConfigParser
- ConfigParser
- SafeConfigParser
三个以此在前者的基础进行扩展, 接口提供额外可选参数, 提供更加复杂的功能, 主要差别应该体现在对 %(value_name)s 进行参数替换 (value_name 为同 section 或者[DEFAULT] 中的其他变量名才行)
这里使用的默认配置文件 default.cfg 内容如下:
- [DEFAULT]
- default_name = lcd
- [Section1]
- an_int = 15
- a_bool = true
- a_float = 3.1415
- baz = fun
- bar = Python
- foo = %(bar)s is %(baz)s!
- name = s1_%(default_name)s ; DEFAULT section's value
基本读写
使用 RawConfigParser 实现配置文件的基本的读写操作.
- import ConfigParser
- test_cfg = "./default.cfg"
- config_raw = ConfigParser.RawConfigParser()
- config_raw.read(test_cfg)
- # 读取配置文件中 [DEFAULT]
- defaults = config_raw.defaults()
- print defaults
- # 读取指定 section 下的 value 值
- a_float = config_raw.getfloat('Section1', 'a_float')
- print "-- number : %f type is : %s"%(a_float ,type(a_float))
- # 设置指定 section 下的 value 值
- # 此时没有写入文件, 保存在内存实例中
- a_float = 2.14159
- config_raw.set('Section1', 'a_float', a_float)
- a_float = config_raw.getfloat('Section1', 'a_float')
- print "-- number : %f type is : %s"%(a_float ,type(a_float))
- # 读取带有参数替换模板的变量, 但是没有替换参数
- print "-- RawConfigParser just get raw value"
- str_foo = config_raw.get('Section1', 'foo')
- print str_foo
对应不同数据类型, 除了调用 get()获取配置文件中的原始内容, 还可以使用对应的接口, getint, getboolean, 其中, 布尔值 True 对应的是 1,yes,true 和 on, False 对应 0,no,false 和 off.
运行结果
- OrderedDict([('default_name', 'lcd')])
- -- number : 3.141500 type is : <type 'float'>
- -- number : 2.141590 type is : <type 'float'>
- -- RawConfigParser just get raw value
- %(bar)s is %(baz)s!
参数替换
相比 RawConfigParser, 对于配置文件中 foo = %(bar)s is %(baz)s! 这种格式的变量, 在读取的时候如果想要取得替换后的值, 需要使用类 ConfigParser 或者 SafeConfigParser .
代码如下
- config = ConfigParser.ConfigParser()
- config.read(test_cfg)
- print "-- ConfigParser can get interpolation"
- ## get 接口添加参数 raw,raw=1 时直接返回配置文件中的值, 不做参数替换
- ## raw 默认为 0, 设置为 0 时, 返回替换后的值
- str_foo = config.get('Section1', 'foo', raw=1)
- # 等同 str_foo = config.get('Section1', 'foo', 1)
- print str_foo
- str_foo = config.get('Section1', 'foo')
- print str_foo
- str_foo = config.get('Section1', 'foo', 0)
- print str_foo
- print "-- After set a new value"
- str_foo = "%(name)s is %(baz)s!"
- config.set('Section1', 'foo', str_foo)
- str_foo = config.get('Section1', 'foo', 1)
- print str_foo
- str_foo = config.get('Section1', 'foo')
- print str_foo
- ## raw=0, 返回替换后的值, 替换的变量是在同 section 下或者 default section 中查找
- str_foo = config.get('Section1', 'name')
- print str_foo
- ## 接口还有另外一个可选参数 vars,
- ## 设置后, 查询配置 values 时, 会优先从 vars 这个 {
- } 寻找匹配的 key 返回
- ## 没有再去寻找配置文件中的.
- print "-- use default value if pass by vars={}"
- a_float = config.get('Section1', 'a_float1', vars={
- 'a_float1':'0.01'
- })
- print "-- number : %f type is : %s"%(float(a_float) ,type(a_float))
运行结果
- -- ConfigParser can get interpolation
- %(bar)s is %(baz)s!
- Python is fun!
- Python is fun!
- -- After set a new value
- %(name)s is %(baz)s!
- s1_lcd is fun!
- s1_lcd
- -- use default value if pass by vars={
- }
- -- number : 0.010000 type is : <type 'str'>
使用默认参数
有些配置参数有时候配置文件中并没有设置, 此时程序中应该有对应的默认值, 当找配置文件中查找不到时, 使用配置值. 注意和上一小节设置 vars={}不同, 此处是优先返回配置文件的值, 没有才返回设置的默认值, 上面则相反.
如下
- ## 设置默认值 name : default_name
- config = ConfigParser.ConfigParser({
- 'name' : 'default_name'
- })
- config.readfp(open('./default.cfg'))
- # 读取存在的配置值, 返回的是配置文件中的值
- str_foo = config.get('Section1', 'name')
- print str_foo
- print "-- use default value"
- config.remove_option('Section1', 'name')
- # 读取不存在的配置值, 返回设置的默认值
- str_foo = config.get('Section1', 'name')
- print str_foo
运行结果
- s1_lcd
- -- use default value
- default_name
使用默认配置文件
程序配置时, 可以设置多个配置文件, 并按照一定的优先级使用相应的配置文件, 比如系统默认有个配置文件, 不同的用户下又使用不同的配置文件, 程序运行时优先使用用户配置文件中的配置参数, 如果用户配置文件不存在或者对应参数没有设置, 再读取系统默认配置文件中的参数值.
此处, 默认配置文件是开头提供的 default.cfg
另新加两个配置文件:
- user1.cfg
- [DEFAULT]
- default_name = user1
- [Section1]
- name = s1_%(default_name)s ; DEFAULT section's value
- user2.cfg
- [DEFAULT]
- default_name = user1
- [Section1]
- name = s1_%(default_name)s ; DEFAULT section's value
我们希望, 参数使用优先级按照 user3.cfg> uer2.cfg> user1.cfg> default.cfg 使用
实现方式如下:
- config = ConfigParser.ConfigParser()
- ## 设置默认的配置文件
- ## 注意此文件不存在会 raise 异常
- config.readfp(open('./default.cfg'))
- ## 设置可选配置文件, 最后优先级最高, 文件不存在则忽略
- config.read(['./user1.cfg', './user2.cfg', './user3.cfg'])
- # readfp 必须先调用后才能调用 read, 否则 read 中都打不开, 会报错
- # config.read(['./user11111111.cfg', './user22222222.cfg'])
- ## 可选文件中找不到的参数, 在 default 中查找
- an_int = config.getint('Section1', 'an_int')
- print "-- number : %f type is : %s"%(an_int ,type(an_int))
- ## 使用可选文件中存在的参数
- str_foo = config.get('Section1', 'name')
- print str_foo
运行结果
- -- number : 15.000000 type is : <type 'int'>
- s1_user2
默认文件需要存在, 运行时加载失败会报错, 其他可选设置文件如果找不到, 直接忽略.
python3 - configparser
可能考虑兼容性, 前面 python2 中实现的三个类在 python3 中依然支持. 对于 python2 提供的参考上一节内容, 接下面我们看看 python3 的使用.
基本读写
同 python2 差不多, 加载配置文件后可以通过诸如 get, getint 的接口读取参数值, 也可以像读取 dict 一样读取配置参数.
读取的配置文件 example.INI 如下
- [DEFAULT]
- serveraliveinterval = 45
- compression = yes
- compressionlevel = 9
- forwardx11 = yes
- [bitbucket.org]
- user = hg
- ;comment
- #comment
- [topsecret.server.com]
- port = 50022
- forwardx11 = no
使用接口读取上述配置文件内容
- import configparser
- config = configparser.ConfigParser()
- print("- Empty config %s"%config.sections())
- print("- Load config file")
- config.read("./example.ini")
- ## 此处返回的 sections list 不包括 default
- print("> config sections : %s"%config.sections())
- print('bitbucket.org' in config ) ## 判断配置文件中是否存在该 section
- print("> Load config file is :")
- for section in config.keys():
- print("[{s}]".format(s=section))
- for key in config[section]:
- print("{k} = {v}".format(k=key, v=config[section][key]))
- ## 如访问 dict 一样读取配置内容
- print("\n- Get value like dict :user = %s"%config['bitbucket.org']['user'])
- conf_bitbucket = config['bitbucket.org']
- print(conf_bitbucket['user'])
- """The DEFAULT section which provides default values for all other sections"""
- print("\n- DEFAULT Section")
- ## default 是所有 section 的默认设置, 备胎...
- for key in config['bitbucket.org']: print(key)
- print("> Get default value : forwardx11 = %s\n"%config['bitbucket.org']['forwardx11'])
- ## 读取不同数据类型的配置参数
- print("\n- Support datatypes")
- forwardx11 = config['bitbucket.org'].getboolean('forwardx11')
- int_port = config.getint('topsecret.server.com', 'port')
- float_port = config.getfloat('topsecret.server.com', 'port')
- print("> Get int port = %d type : %s"%(int_port, type(int_port)))
- print("> Get float port = %f type : %s"%(float_port, type(float_port)))
运行结果如下:
- - Empty config []
- - Load config file
- > config sections : ['bitbucket.org', 'topsecret.server.com']
- True
- > Load config file is :
- [DEFAULT]
- serveraliveinterval = 45
- compression = yes
- compressionlevel = 9
- forwardx11 = yes
- [bitbucket.org]
- user = hg
- serveraliveinterval = 45
- compression = yes
- compressionlevel = 9
- forwardx11 = yes
- [topsecret.server.com]
- port = 50022
- forwardx11 = no
- serveraliveinterval = 45
- compression = yes
- compressionlevel = 9
- - Get value like dict :user = hg
- hg
- - DEFAULT Section
- user
- serveraliveinterval
- compression
- compressionlevel
- forwardx11
- > Get default value : forwardx11 = yes
- - Support datatypes
- > Get int port = 50022 type : <class 'int'>
- > Get float port = 50022.000000 type : <class 'float'>
默认返回
在读取配置参数时, 设置如果在配置文件中查找不到指定值, 则默认返回的值.
在指定 section 和 default 中都找不到查找的值, 就会直接返回设置的 fallback, 而不是 raise 错误.
- print("\n- Return Fallback")
- print("> Get value user = %s"%(config.get('bitbucket.org', 'user')))
- print("> Get value user = %s"%(config.get('bitbucket.org', 'user', fallback="fallback_name")))
- print("> Get value forwardx11 = %s"%(config.getboolean('bitbucket.org', 'forwardx11', fallback=False)))
- print("> Get value forwardx22 = %s"%(config.getboolean('bitbucket.org', 'forwardx22', fallback=False)))
- print("> Get value user2 = %s"%(config.get('bitbucket.org', 'user2', fallback="fallback_name")))
运行结果如下:
- - Return Fallback
- > Get value user = hg
- > Get value user = hg
- > Get value forwardx11 = True
- > Get value forwardx22 = False
- > Get value user2 = fallback_name
参数替换
在 python2 中提到的参数替换, pyton3 中默认使用的 BasicInterpolation(), 直接支持, 在上面就提到, 这种替换, 变量必须是同个 section(包括 default), 如果要使用到其他 section 的参数, 就需要使用 ExtendedInterpolation(), 并且, 语法上会有些许不同.
如下, basic_interpolation.INI 是基础的替换配置文件, 和 python2 一样
- [Paths]
- home_dir: /Users
- my_dir: %(home_dir)s/lumberjack
- my_pictures: %(my_dir)s/Pictures
而以下这个, 扩展到参数可以使用不同的 section, 在 extended_interpolation.INI 中, 替换的参数写法是 ${section_name: value_name}
- [Common]
- home_dir: /Users
- library_dir: /Library
- system_dir: /System
- macports_dir: /opt/local
- [Frameworks]
- Python: 3.2
- path: ${
- Common:system_dir
- }/Library/Frameworks/
- [Arthur]
- nickname: Two Sheds
- last_name: Jackson
- my_dir: ${
- Common:home_dir
- }/twosheds
- my_pictures: ${
- my_dir
- }/Pictures
- python_dir: ${
- Frameworks:path
- }/Python/Versions/${
- Frameworks:Python
- }
对以上两个配置文件进行读取, 如下代码
- print("\n- BasicInterpolation")
- #default : config = configparser.ConfigParser(interpolation=configparser.BasicInterpolation())
- ## 默认使用的 interpolation 就是 BasicInterpolation()
- config.read("./basic_interpolation.ini")
- print("> Get raw value %s"%(config.get('Paths', 'my_dir', raw = 1)))
- print("> Get value %s"%(config.get('Paths', 'my_dir', raw = 0)))
- print("\n- ExtendedInterpolation - other sections")
- config = configparser.ConfigParser(interpolation=configparser.ExtendedInterpolation())
- config.read("./extended_interpolation.ini")
- print("> Get raw value %s"%(config.get('Arthur', 'python_dir', raw = 1)))
- print("> Get value %s"%(config.get('Arthur', 'python_dir', raw = 0)))
运行结果 :
- - BasicInterpolation
- > Get raw value %(home_dir)s/lumberjack
- > Get value /Users/lumberjack
- - ExtendedInterpolation - other sections
- > Get raw value ${
- Frameworks:path
- }/Python/Versions/${
- Frameworks:Python
- }
- > Get value /System/Library/Frameworks//Python/Versions/3.2
- pyYAML
- jason
参考
- python2-ConfigParser
- python3-configparser
YAML 语言
?
来源: http://www.bubuko.com/infodetail-3500343.html