Hello! 欢迎来到小浪资源网!

迈向轻松的 Python 配置文件版本 1


介绍

正如上一篇文章所述,简单化版本充满了可扩展性、可维护性和可扩展性等问题。

版本 Ø 的一个简单扩展是尝试将 python 配置详细信息隐藏在属性类后面。 这是实现一个伪数据类,它公开一组属性,允许开发人员简单地执行属性 setget 调用来检索和保留属性值。

从维护者的角度来看,此实现应该支持以下功能。

  1. 允许自动创建配置节(如果缺少)
  2. 允许自动创建属性值(如果缺失)
  3. 属性应该实现为读通和写通。
  4. 为了避免上述启动成本,因为应用程序在整个应用程序中实例化此类,该类应该是单例。

班级代表

下面的 uml 类图描述了一个满足简介中要求的类。 configuratonproperties 类通过受保护的方法 .createmissingsections 和 .createmissingkeys

满足要求 1 和 2

迈向轻松的 Python 配置文件版本 1

立即学习Python免费学习笔记(深入)”;

创建实施

创建缺失的部分

以下代码显示了实现。 请注意,其他部分需要对此方法进行代码更新

section_general:  str = 'general' section_database: str = 'database'  def _createmissingsections(self):     """     create missing sections.  add additional calls for     each defined section     """     self._createmissingsection(section_general)     self._createmissingsection(section_database) 

缺失部分代码如下

def _createmissingsection(self, sectionname: str):     """     only gets created if it is missing     args:         sectionname: the potential section to create     """     hassection: bool = self._configparser.has_section(sectionname)     self.logger.info(f'hassection: {hassection} - {sectionname}')     if hassection is false:         self._configparser.add_section(sectionname) 

创建丢失的钥匙

以下代码显示了实现。 再次注意,如果我们添加附加部分,开发人员必须为新部分添加附加循环

general_preferences: dict[str, str] = {     'debug':    'false',     'loglevel': 'info' }  database_preferences: dict[str, str] = {     'dbname': 'example_db',     'dbhost': 'localhost',     'dbport': '5432' }  def _createmissingkeys(self):     """     create missing keys and their values.  add additional calls for     each defined section.     """     for keyname, keyvalue in general_preferences.items():         self._createmissingkey(sectionname=section_general, keyname=keyname, defaultvalue=keyvalue)     for keyname, keyvalue in database_preferences.items():         self._createmissingkey(sectionname=section_database, keyname=keyname, defaultvalue=keyvalue) 

缺失的关键代码如下。 请注意,任何丢失的密钥都会立即保留。

def _createmissingkey(self, sectionname: str, keyname: str, defaultvalue: str):     """     only gets created if it is missing.  the configuration file is updated     immediately for each missing key and its value      args:         sectionname:   the section name where the key resides         keyname:       the key name         defaultvalue:  itsß value     """     if self._configparser.has_option(sectionname, keyname) is false:         self._configparser.set(sectionname, keyname, defaultvalue)         self._saveconfiguration() 

类属性

要求 3 的示例实现如下。

字符串属性

请注意,通过设置属性并立即保留它,设置属性会直写到配置文件。 读取属性实际上是通读,因为我们如何立即写入设置属性。

@property def dbname(self) -> str:     return self._configparser.get(section_database, 'dbname')  @dbname.setter def dbname(self, newvalue: str):     self._configparser.set(section_database, 'dbname', newvalue)     self._saveconfiguration() 

整数属性

整数属性使用 .getint 方法来检索值。 设置属性时,开发人员必须手动将其转换为字符串

@property def dbport(self) -> int:     return self._configparser.getint(section_database, 'dbport')  @dbport.setter def dbport(self, newvalue: int):     self._configparser.set(section_database, 'dbport', str(newvalue))     self._saveconfiguration() 

布尔属性

布尔属性使用 .getboolean 方法来检索它们的值。 设置属性时,开发人员必须手动将其转换为字符串。

section_general:  str = 'general'  @property def debug(self) -> bool:     return self._configparser.getboolean(section_general, 'debug')  @debug.setter def debug(self, newvalue: bool):     self._configparser.set(section_general, 'debug', str(newvalue))     self._saveconfiguration() 

枚举属性

我不会在本文中介绍枚举属性。 有两种方法可以通过名称或值来保存它们。 每种机制都需要稍微不同的方式将值反序列化回枚举类型

访问和修改属性

以下代码片段演示了如何访问和修改属性。

from logging import logger from logging import getlogger from logging import basicconfig from logging import info  logger_name: str = 'tutorial'  basicconfig(level=info)  config: configurationproperties = configurationproperties()  logger: logger = getlogger(logger_name)  logger.info(f'{config.debug=}') logger.info(f'{config.loglevel=}') # logger.info('change the values and show them') # config.debug = true logger.info(f'{config.debug=}') config.loglevel = 'warning' logger.info(f'{config.loglevel=}') # logger.info('**** database section ****') logger.info(f'{config.dbname=}') logger.info(f'{config.dbhost=}') logger.info(f'{config.dbport=}') # logger.info('change db values and print them') config.dbname = 'ozzeedb' config.dbhost = 'ozzeehost' config.dbport = 6666  logger.info(f'{config.dbname=}') logger.info(f'{config.dbhost=}') logger.info(f'{config.dbport=}') 

上面的代码片段产生以下输出

INFO:Tutorial:Configuration file existed INFO:Tutorial:hasSection: True - General INFO:Tutorial:hasSection: True - Database INFO:Tutorial:config.debug=True INFO:Tutorial:config.logLevel='Warning' INFO:Tutorial:Change the values and show them INFO:Tutorial:config.debug=True INFO:Tutorial:config.logLevel='Warning' INFO:Tutorial:**** DataBase Section **** INFO:Tutorial:config.dbName='ozzeeDb' INFO:Tutorial:config.dbHost='ozzeeHost' INFO:Tutorial:config.dbPort=6666 INFO:Tutorial:Change db values and print them INFO:Tutorial:config.dbName='ozzeeDb' INFO:Tutorial:config.dbHost='ozzeeHost' INFO:Tutorial:config.dbPort=6666 

结论

本文的源代码在这里。 支持类singletonv3在这里

实现的结果最初让我作为代码的使用者感到满意。 我能够获取和设置类型属性。 然而,作为代码的维护者,每当我添加新的部分和新的属性时,我都必须手动更新代码数据结构和代码循环。 此外,我真正从中得到的只是一种每当我在不同应用程序中需要新配置属性时就可以使用的机制/模式。

优点

  • 轻松类型安全地访问应用程序属性
  • 在应用程序的不同部分调用单例可以提供对属性的一致且可靠的访问,无论应用程序的哪个部分修改了值

缺点

  • 添加新属性的更新很乏味
  • 大量样板代码
  • 无法跨各种应用程序重用。 本质上,我只有一个模板

请参阅我的下一篇文章,其中记录了替代实现,以解决我列出的缺点,同时保留优点。

相关阅读