在 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 中加载模块范围的配置的主要内容,如果未能解决你的问题,请参考以下文章