从类中加载配置,使其行为类似于属性

时间:2018-01-19 23:50:10

标签: python python-2.7 python-module

我试图为python创建一个yaml驱动的配置模块,它从平面yaml文件加载,并可选择从sys.argv加载params。它还将加载的属性保存到局部变量(这很难看,但每次引用config时,它仍然优于解析yaml文件。)

我有这个工作,但我必须导入它的方式似乎过度,而不是非常pythonic。是否有更优雅的方式来构建它:

  • 我可以使用单个导入语句
  • 我可以确保配置没有被加载多次(在使用它的不同模块中)而不是绝对必要

结构:

/app
    /__init__.py
    /__main__.py # calls __init__.py
    /config.yaml
    /applib
        /__init__.py
        /__config_loader.py

在应用程序的主__init__.py中,我按如下方式加载配置:

from applib.config_loader import Config; config = Config()
#                                          ^ ew!

config_loader.py中,我有:

import argparse
import yaml

class Config:
    _config = None

    @property
    def config(self):
        if self._config is not None:
            print('Using what we already loaded')
        return self._config or Config()

    def __init__(self):
        if self._config is None:
            print('Loading config')

            with open(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'config.yaml')) as yaml_config_file:
                self._config = yaml.load(yaml_config_file)

            parser = argparse.ArgumentParser(description = 'MyApp')
            parser.add_argument('--an_arg')
            args = parser.parse_args()

    def __getattr__(self, name):
        return self._config[name] or None

当然不是让这个工作起来的最漂亮的方式,而且似乎我无法理解python中旧的和新的做事方式使得情况过于复杂。

我希望能够加载它:

from applib.config_loader import config

print(config['an_arg'])

1 个答案:

答案 0 :(得分:1)

解决问题的简单方法是将此行:

config = Config()

定义类Config之后。但是有一个更简单的解决方案:可以删除config_loader.py中大约一半的代码。像这样:

import argparse
import yaml

class _Config:
    def __init__(self):
        print('Loading config')
        with open(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'config.yaml')) as yaml_config_file:
            self.config = yaml.load(yaml_config_file)
        parser = argparse.ArgumentParser(description = 'MyApp')
        parser.add_argument('--an_arg')
        self.args = parser.parse_args()

    def __getattr__(self, name):
        try:
            return self.config[name]
        except KeyError:
            return getattr(self.args, name)

config = _Config()

您的客户端代码现在:

from config_loader import config

您可以通过常规方式config.xxx访问config中的属性。您不需要处理单例对象行为或类变量。 _Config前面的下划线保证在加载模块时只调用一次类构造函数。只能通过名为config的变量访问该类。

我还修复了第二个未讨论过的问题:你没有在Config构造函数中使用变量“args”,因此实际上并没有对命令行解析器的输出做任何事情。我将args变成了一个成员变量并适当地修改了__getattr__函数。