在 python 中加载模块范围的配置

Posted

技术标签:

【中文标题】在 python 中加载模块范围的配置【英文标题】:Load module-wide config in 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 类。

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

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

【问题讨论】:

【参考方案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 是为了好玩,但从未在大型项目中亲自使用过它。现实情况是,您可能会遇到让您的代码对其他开发人员来说很奇怪的问题。

【讨论】:

以上是关于在 python 中加载模块范围的配置的主要内容,如果未能解决你的问题,请参考以下文章

如何在 webpack 模块中加载备用 jquery?

在没有前缀的目录中加载所有模块(文件)

PyImport_ImportModule,可以从内存中加载模块吗?

模块不会在应用程序中加载

如何在 C/C++ 程序中加载内核模块

如何在android原生中加载RN页面