Python中常用的配置文件
常见的配置文件
软件开发过程中,配置文件是经常打交道的东西。对于一些复杂的程序来说,需要使用配置文件来配置一些参数。
比如说,测试环境、预生产环境和生产环境的地址,mysql的地址,帐号,密码等信息。因为部署的环境不同,所对的应内容就不同,在这种情况下就需要根据不同的部署环境配置不同的参数。
通常,配置文件中的内容都是以 key--value
的形式存在。
- py文件
在Python中,字典类型,恰好是key--value
的形式;变量在某种意义上来说,也是key--value
的形式。所以,在Python项目中,可以采用.py
文件作为配置文件 - yaml文件
yaml文件是比较新的一种配置文件格式,通俗易懂,在Python、Java和PHP等项目环境中均可使用。但也有个头痛的地方,就是对齐和空格要注意雨露均沾,这个有点像Python的语法,所以在Python项目中经常结合起来使用。
常见的yaml文件后缀为.yaml
、.yml
- ini文件
是windows的系统配置文件所采用的存储格式,统管windows的各项配置,在windows下用的比较多,在Linux下的项目中也能使用。ini文件
是比较传统的配置文件,使用频率还是比较高的,但ini文件
有比较严重缺点,只支持一层参数,太复杂的项目就不适用了,现在逐渐用的比较少了。
其后缀是.ini
。例如:端口配置.ini
。
其余的配置文件,例如conf文件、xml文件,这两种文件,在Python项目中,接触的比较少,这里就不一一举例说明了。
接着以上篇文章logging日志进行举例,通过编写配置文件,来生成不同的日志文件信息。
logger.py
import logging
class LoggerHandler(logging.Logger):
# 初始化 Logger
def __init__(self,
name='root',
logger_level= 'DEBUG',
file=None,
logger_format = " [%(asctime)s] %(levelname)s [%(filename)s %(funcName)s] [ line:%(lineno)d ] %(message)s"
):
# 1、设置logger收集器,继承logging.Logger
super().__init__(name)
# 2、设置日志收集器level级别
self.setLevel(logger_level)
# 5、设置 handler 格式
fmt = logging.Formatter(logger_format)
# 3、设置日志处理器
# 如果传递了文件,就会输出到file文件中
if file:
file_handler = logging.FileHandler(file)
# 4、设置 file_handler 级别
file_handler.setLevel(logger_level)
# 6、设置handler格式
file_handler.setFormatter(fmt)
# 7、添加handler
self.addHandler(file_handler)
# 默认都输出到控制台
stream_handler = logging.StreamHandler()
# 4、设置 stream_handler 级别
stream_handler.setLevel(logger_level)
# 6、设置handler格式
stream_handler.setFormatter(fmt)
# 7、添加handler
self.addHandler(stream_handler)
py文件
变量方式
pyconfig.py
import time
from configfile import logger
curTime = time.strftime("%Y-%m-%d %H_%M", time.localtime())
file = "Web_Autotest_{}.log".format(curTime)
if __name__ == '__main__':
logger = logger.LoggerHandler(file=file)
logger.info('hello world!')
引入时间模块,设置变量为日志文件名称file
,将file
变量导入LoggerHandler
生成了日志文件Web_Autotest_2021-09-03 10_54.log
类方式
类方式有一个好处,继承。
比如测试环境,日志级别要比较详细,需要debug级别方便定位问题,而生产环境,日志级别只需要info级别即可
pyconfig2.py
import sys
import time
from configfile import logger
curTime = time.strftime("%Y-%m-%d %H_%M", time.localtime())
class LoggerConfig:
name = 'Web_Autotest'
logger_level= 'INFO'
file ="Web_Autotest_{}.log".format(curTime)
# 继承LoggerConfig类
class ProductLoggerConfig(LoggerConfig):
logger_level = 'DEBUG'
if __name__ == '__main__':
# 如果系统环境是Windows,则为测试环境
if sys.platform =='win32':
logger = logger.LoggerHandler(name=LoggerConfig.name,logger_level=LoggerConfig.logger_level,file=LoggerConfig.file)
# 如果系统环境是linux,则为生产环境
elif sys.platform =='linux':
logger = logger.LoggerHandler(name=ProductLoggerConfig.name,logger_level=ProductLoggerConfig.logger_level,file=ProductLoggerConfig.file)
else:
logger = logger.LoggerHandler(name=LoggerConfig.name,logger_level=LoggerConfig.logger_level,file=LoggerConfig.file)
logger.info('hello')
logger.debug('world!')
如果系统环境是Windows
,则会使用LoggerConfig
类变量的内容,如果系统环境是linux
,则会使用ProductLoggerConfig
类变量的内容,ProductLoggerConfig
类继承了LoggerConfig
类,所以name
和 file
都是LoggerConfig
类中的变量,唯独 logger_level = 'DEBUG'
yaml文件
yaml文件基础知识
安装:
pip install pyyaml
yaml语法规则:
- 大小写敏感
- 使用缩进表示层级关系,缩进空格数目不重要,只要相同层级的元素左侧对齐即可(虽然编辑器中一个Tab键是4个空格,一般不会出错,但尽量用空格缩进)
#
表示注释
yaml支持的数据结构有3种:
- 对象:键值对的集合,又称映射(mapping)/哈希(hashes)/字典(dictionary)
- 数组:一组按次序排列的值,又称序列(sequence)/列表(list)
- 纯量(scalars):单个的,不可再分的值
对象:对象的一组键值,使用冒号表示(注意:编写的时候最好冒号前后各空一个空格)
animal : dog
类似于python中的字典
{animal : "dog"}
数组:一组连词线构成的行,组成一组数组
- animal
- vegetables
- meet
- people
类似于python中的列表
["animal","vegetables","meet","people"]
复合结构:对象和数组可以结合使用,形成复合结构
language:
- Python
- Java
- PHP
websites:
Python : python.org
Java : java.com
YAML : yaml.org
转换为python形式:
{language:["Python","Java","PHP"],websites:{"Python":"python.org","Java":"java.com","YAML":"yaml.org"}}
yaml作为配置文件
config.yaml
logger:
name : WebAutotest
loggerleve : INFO
file : WebAutotest.log
或者不用加引号,都是一样的
config2.yaml
logger:
name : "WebAutotest"
loggerleve : "INFO"
file : "WebAutotest.log"
python读取yaml文件
yamlconfig.py
import yaml
# 读取yaml配置,加载配置项
f = open(r'./config.yaml',encoding='utf-8')
data = yaml.load(f.read(),Loader=yaml.FullLoader)
print(data)
f.close()
结果:
{'logger': {'name': 'WebAutotest', 'loggerleve': 'INFO', 'file': 'WebAutotest.log'}}
python写入yaml文件
yamlconfig.py
import yaml
data = {'dbtest': {'host': '192.168.134.1', 'user': 'test', 'pwd': 'test', 'port': 3306}}
f2 = open(r'./config3.yaml',encoding='utf-8',mode='w') # 如果是追加,则将'w'改为'a+'
yaml.dump(data,f2,allow_unicode=True)
f2.close()
此时,新增了一个 config3.yaml
文件,写入的内容就是
config3.yaml
dbtest:
host: 192.168.134.1
port: 3306
pwd: test
user: test
不过一般情况下,对于配置文件只进行读取操作,不会用代码对配置文件进行写入操作,需要对配置文件进行修改,手动修改即可
yaml文件操作封装
封装成函数
# 读取 yaml文件
def read_yaml(file,encoding='utf-8'):
with open(file,encoding=encoding) as f:
return yaml.load(f.read(),Loader=yaml.FullLoader)
# 写入 yaml文件
def write_yaml(file,data,encoding='utf-8'):
with open(file, encoding=encoding,mode='w') as f:
yaml.dump(data,stream=f,allow_unicode=True)
封装成类
如果有需要,可以封装成类,推荐将 “读” 与 “写” 两个操作分开,这样不容易造成冲突
import yaml
# 读取yaml文件
class ReadYaml():
def __init__(self, path, param=None):
self.path = path # 文件路径
self.param = param # 不传默认获取所有数据
# 获取yaml文件中的数据
def get_data(self,encoding='utf-8'):
with open(self.path, encoding=encoding) as f:
data = yaml.load(f.read(), Loader=yaml.FullLoader)
# (有点多此一举,不要也行)
if self.param == None:
return data # 返回所有数据
else:
return data.get(self.param) # 获取键为param的值
# 写入yaml文件
class Writeyaml():
def __init__(self, path, message):
self.path = path
self.message = message
# 追加内容
def add_data(self, encoding="utf-8"):
with open(self.path, encoding=encoding, mode="a+") as f:
yaml.dump(self.message, stream=f, allow_unicode=True)
# 重写文件内容
def change_data(self,encoding='utf-8'):
with open(self.path, encoding=encoding, mode='w') as f:
yaml.dump(self.message, stream=f, allow_unicode=True)
if __name__ == "__main__":
filepath = r'./test.yaml'
data = ReadYaml(filepath).get_data()
# data = ReadYaml(filepath,'logger').get_data()
print(data)
message = {'dbtest': {'host': '192.168.134.1', 'user': 'test', 'pwd': 'test', 'port': 3306}}
Writeyaml(path=filepath, message=message).change_data()
Writeyaml(path=filepath, message=data).add_data()
ini文件
ini文件基础知识
ini结构:
- 片段(section)
- 选项(option)(相当于python字典里的key)
- 值(value)
ini文件作为配置文件
config.ini
[student]
name = ["丽丽","lili"]
age = 18
favor = {"sports":"football","food":"apple"}
python读取ini文件
iniconfig.py
from configparser import ConfigParser
# 初始化
config = ConfigParser()
# 读取文件
config.read(r'config.ini',encoding='utf-8')
data = config.get('student','name')
print(data)
print(type(data))
# 结果
["丽丽","lili"]
<class 'str'>
这个读取方式有点特殊,要先读取片段student
,再通过读取选项name
来获取里面的值 ["丽丽","lili"]
通过python读取的ini文件
里的值,都是字符串类型,所以data
为字符串类型,并不是列表类型,如果内容比较复杂的时候,使用python读取的ini文件里的内容,还要再进行处理, 就会比较麻烦。
所以一般情况下,会使用 yaml
文件作为配置文件,与Python项目进行结合
python修改ini文件
ini文件
里的内容类似于字典,获取value
后,可对其进行修改
iniconfig.py
from configparser import ConfigParser
# 初始化
config = ConfigParser()
# 读取文件
config.read(r'../file/config.ini',encoding='utf-8')
# 将age修改为20
config['student']['age'] = '20'
f2 = open(r'../file/config.ini',mode='w',encoding='utf-8')
config.write(f2)
此时,config.ini
文件中,age
变为了20
config.ini
[student]
name = ["丽丽","lili"]
age = 20
favor = {"sports":"football","food":"apple"}
ini文件操作封装
- 第一种是继承
ConfigParser
类
from configparser import ConfigParser
class HandleConfig(ConfigParser):
def __init__(self, filename):
# 调用父类的init方法
super().__init__()
self.filename = filename
self.read(filename,encoding="utf8")
def write_data(self, section, options, value):
"""写入数据的方法"""
self.set(section, options, value)
self.write(fp=open(self.filename, "w"))
这时,如果要获取ini文件
里的值,实例化 HandleConfig
类后,依旧使用 get
方法即可
修改ini文件
里的值,调用 write_data
进行传参即可
conf = HandleConfig("config.ini")
# 读取片段`student`,再通过读取选项`name`来获取里面的值 `["丽丽","lili"]`
data = config.get('student','name')
- 第二种是自己封装一个类
开关配置文件
setting.ini
[switch]
open = True
生产环境配置文件
product.ini
[api]
pre_url = http://product.com/mvc/api
[db]
host = product.com
user = product
pwd = product
port = 3306
[data]
admin_user = 17122223333
admin_pwd = 123456
[log]
[log]
file_handler = INFO
console_handler = ERROR
测试环境配置文件
test.ini
[api]
pre_url = http://test.com/mvc/api
[db]
host = test.com
user = test
pwd = test
port = 3306
[data]
admin_user = 17111112222
admin_pwd = 123456
[log]
file_handler = INFO
console_handler = DEBUG
此时,需先判定是测试环境还是生产环境
import configparser
class ReadConfig:
def __init__(self):
# 实例化对象
self.config = configparser.ConfigParser()
# 加载文件
self.config.read('setting.ini', encoding='utf-8') # 先加载开关的配置
open = self.config.getboolean('switch', 'open') # 总开关
# 灵活切换测试环境
if open: # 如果是True就加载 生产环境配置文件
self.config.read('product.ini', encoding='utf-8') # open是True
else: # 如果是False 就加载 测试环境配置文件
self.config.read('test.ini', encoding='utf-8') # open是False
def get(self, section, option):
return self.config.get(section, option)
def getboolean(self, section, option):
return self.config.getboolean(section, option)
def getint(self, section, option):
return self.config.getint(section, option)
这种方式是比较“笨”的方式,但也实现了读取配置文件的功能