【问题标题】:Load module-wide config in python在 python 中加载模块范围的配置
【发布时间】:2017-12-04 14:54:10
【问题描述】:

让我们假设,在一个模块中有以下简约的 Python 类,例如Module:

module/
   __init__.py
   db.py
   document.py

db.py

import yaml

class DB(object):
    config = {}

    @classmethod
    def load_config(cls, config_path):
        cls.config = yaml.load(open(config_path, 'r').read())

和document.py

from .db import DB

class Document(object):
    db = None

    def __init__(self):
        self.db = DB()

最终用户将使用如下Module

from Module import DB, Document

DB.load_config('/path/to/config.yml')

Document.do_some_stuff()

doc1 = Document()
doc2 = Document.find(...)
doc2.update_something(...)
doc2.save()

预计Document 类及其每个实例都将在内部使用用户指定的配置访问类DB。但是,由于 Document 执行 DB 类 (from .db import DB) 的内部导入,它会收到一个带有默认配置的“新鲜”DB 类。

我做了很多搜索,大部分问题和答案都是关于模块范围的配置,但最终用户没有指定。

我怎样才能实现这样的功能?我猜这里存在一些架构问题,但最简单的解决方法是什么?

【问题讨论】:

    标签: python oop inheritance module package


    【解决方案1】:

    也许这不是最合适的答案,但几个月前,我为此目的编写了一个名为 aconf 的模块。它是一个基于内存的 Python 全局配置模块,用 8 行代码编写。这个想法是您可以执行以下操作:

    您创建一个Config 对象来强制用户输入您的程序所需的配置(在这种情况下,它位于config.py 内部):

    """ 'Config' class to hold our desired configuration parameters. 
    
    Note:
        This is technically not needed. We do this so that the user knows what he/she should pass 
        as a config for the specific project. Note how we also take in a function object - this is
        to demonstrate that one can have absolutely any type in the global config and is not subjected
        to any limitations.
    """
    
    from aconf import make_config
    
    class Config:
        def __init__(self, arg, func):
            make_config(arg=arg, func=func)
    

    您在整个模块中使用您的配置(在本例中,在 functionality.py 内部):

    """ Use of the global configuration through the `conf` function. """
    
    from aconf import conf
    
    class Example:
        def __init__(self):
            func = conf().func
            arg = conf().arg
    
            self.arg = func(arg)
    

    然后使用它(在这种情况下在main.py 内部):

    from project.config import Config
    from project.functionality import Example
    
    # Random function to demonstrate we can pass _anything_ to 'make_config' inside 'Config'.
    def uppercase(words):
        return words.upper()
    
    # We create our custom configuration without saving it.
    Config(arg="hello world", func=uppercase)
    
    # We initialize our Example object without passing the 'Config' object to it.
    example = Example()
    print(example.arg) 
    # >>> "HELLO WORLD"
    

    整个aconf模块如下:

    __version__ = "1.0.1"
    import namedtupled
    
    def make_config(**kwargs):
        globals()["aconf"] = kwargs
    
    conf = lambda: namedtupled.map(globals()["aconf"])
    config = lambda: globals()["aconf"]
    

    ...本质上,您只需在运行时将配置保存到globals()

    这太愚蠢了,我想知道是否应该允许你这样做。我写aconf 是为了好玩,但从未在大型项目中亲自使用过它。现实情况是,您可能会遇到让您的代码对其他开发人员来说很奇怪的问题。

    【讨论】:

      猜你喜欢
      • 2011-05-13
      • 2018-11-25
      • 1970-01-01
      • 2014-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多