Python配置文件实现
实现目标:
- 支持配置文件继承
- 支持本地配置文件
- 支持配置文件别名
- 简单的配置文件操作
最新的代码可以参考 https://github.com/blackmatrix7/matrix-toolkit/blob/master/toolkit/config.py
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2017/8/18 上午9:31 # @Author : Matrix # @Github : https://github.com/blackmatrix7/ # @Blog : http://www.cnblogs.com/blackmatrix/ # @File : config.py # @Software: PyCharm import os __author__ = 'blackmatrix' class ConfigMixin: """ Config混合类,支持部分dict协议,实现以类似操作dict的方式操作配置文件。 """ def __setattr__(self, key, value): raise AttributeError def __setitem__(self, key, value): raise AttributeError def __delitem__(self, key): raise AttributeError def __getitem__(self, item): try: return getattr(self, item) except AttributeError as ex: raise KeyError('{0} object has no key {1}'.format(self.__class__.__name__, item)) from ex def __iter__(self): return (k for k in dir(self) if k.upper() == k) def __contains__(self, key): return hasattr(self, key) def items(self): return {k: getattr(self, k, None) for k in dir(self) if k.upper() == k}.items() def get(self, item, value=None): return getattr(self, item, value) class BaseConfig(ConfigMixin): """ 配置文件基类 """ # 项目路径 PROJ_PATH = os.path.abspath('') def get_current_config(config_name='default'): """ 对本地配置文件的支持,当项目根目录存在localconfig.py文件时 优先从localconfig.py中读取配置,如果不存在读取config.py的配置。 localconfig.py 应该加入git的忽略文件 :return: """ try: from localconfig import configs current_config = configs[config_name] except ImportError: from config import configs current_config = configs[config_name] return current_config
使用示例:
在项目根目录创建 config.py 和 localconfig.py。
localconfig.py可以不创建(如果不需要本地配置文件的话),如果创建localconfig.py,需要在.gitignore中,将localconfig.py排除掉。
当项目根目录同时存在config.py 和 localconfig.py时,优先读取localconfig.py的配置项。
config.py 完整代码:
from toolkit.config import BaseConfig, get_current_config __author__ = 'blackmatrix' class DefaultConfig(BaseConfig): """ 配置文件的具体实现,所有的配置项都必须是全部大写 """ # DEBUG DEBUG = False # Cache CACHE_MEMCACHED_SERVERS = ['127.0.0.1:11211'] CACHE_KEY_PREFIX = '' # RabbitMQ RABBITMQ_HOST = '127.0.0.1' RABBITMQ_PORT = 5672 RABBITMQ_USER = 'user' RABBITMQ_PASS = 'password' """ 以下为测试用数据 """ class BaseDemoConfig(BaseConfig): # HOST HOST = '127.0.0.1' """ 对于需要通过其他属性运算获得的属性参数,需要定义在特性中 """ LOGIN_URL = property(lambda self: 'http://{host}/login'.format(host=self.HOST)) class DemoConfig01(BaseDemoConfig): # HOST HOST = '192.168.1.10' class DemoConfig02(BaseDemoConfig): # HOST HOST = '10.10.10.10' default = DefaultConfig() demo01 = DemoConfig01() demo02 = DemoConfig02() configs = {'default': default, 'demo01': demo01, 'demo02': demo02} # 读取配置文件的名称,在具体的应用中,可以从环境变量、命令行参数等位置获取配置文件名称 config_name = 'default' current_config = get_current_config(config_name)
在config.py模块中:
每套配置都为独立的类,继承自BaseConfig,并将其实例化。
如有必要,在多套配置文件类中,可以互相继承。比如DemoConfig01继承自BaseDemoConfig。
在配置文件类的继承中,比较特别的是需要通过其他属性参与运算获取的配置项,需要使用property定义。
例如下面示例代码的LOGIN_URL,需要通过HOST计算得来。
那么就必须写成 LOGIN_URL = property(lambda self: 'http://{host}/login'.format(host=self.HOST))
而不能写成 LOGIN_URL = 'http://{host}/login'.format(host=self.HOST) ,否则在配置文件类的继承时,会出现和预想不一致的情况。
因为在父类(BaseDemoConfig)创建的时候,LOGIN_URL已经通过计算生成。
子类(DemoConfig01)继承自BaseDemoConfig,即使对HOST进行修改,也不会影响到LOGIN_URL的值。那么子类的LOGIN_URL一直是父类创建时的状态。
class BaseDemoConfig(BaseConfig): # HOST HOST = '127.0.0.1' """ 对于需要通过其他属性运算获得的属性参数,需要定义在特性中 """ LOGIN_URL = property(lambda self: 'http://{host}/login'.format(host=self.HOST)) class DemoConfig01(BaseDemoConfig): # HOST HOST = '192.168.1.10' class DemoConfig02(BaseDemoConfig): # HOST HOST = '10.10.10.10' default = DefaultConfig() demo01 = DemoConfig01() demo02 = DemoConfig02()
configs变量为dict,存储配置文件别名和对应的配置文件对象。
configs = {'default': default, 'demo01': demo01, 'demo02': demo02}
模块存储名为config_name的变量,为配置文件别名。
# 读取配置文件的名称,在具体的应用中,可以从环境变量、命令行参数等位置获取配置文件名称 config_name = 'default'
再声明变量current_config,由get_current_config(config_name)取值,表示当前的配置文件。
get_current_config会根据配置文件别名,加载不同的配置项。
current_config = get_current_config(config_name)
localconfig.py也进行如此配置,甚至可以从config.py中继承。
唯一不同的是,localconfig.py中,不需要声明config_name和current_config变量。
配置文件的使用:
在需要使用配置项的代码中,使用如下代码导入当前的配置文件
# 读取当前配置项 # current_config会根据当前的config_name获取到匹配的配置文件对象 # 如果项目根目录存在localconfig.py,则优先从localconfig.py中读取 from config import current_config
获取配置文件中的属性
# 获取配置文件中的属性 # 配置文件对象,支持以.(点号)运算符获取对象的属性,也支持以key的形式获取对象的属性 # 以下两种方式都能获取的配置项 RABBITMQ_HOST = current_config.RABBIT_HOST RABBITMQ_PORT = current_config['RABBITMQ_PORT']
配置文件支持遍历
keys = [key for key in current_config] assert isinstance(keys, list) values = {k: v for k, v in current_config.items()} assert isinstance(values, dict)