通过 merging/updating 属性将配置加载到模块的命名空间

Load-once config by merging/updating properties onto module's namespace

在Python中采用以下配置单例class:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals, print_function
from builtins import *
import sys

class Config(object):

    __instance = None

    def __new__(cls):
        if cls.__instance is None:
            cls.__instance = super(Config, cls).__new__(cls)
            cls.__instance.__initialized = False
        return cls.__instance

    def __init__(self):
        print('INIT')
        if self.__initialized: 
            return
        self.__initialized = True

        self._defaults = {"foo": True, "bar": False}

        for k, v in self._defaults.items():
            setattr(self, k, v)

    def reload(self):
        print(self)
        if not self._defaults:
            return
        for k, v in self._defaults.items():
            setattr(self, k, v)

我可以编写一个测试来验证属性设置和更新是否正确:

import config; config = config.Config()

print(config)
print(config.foo)
assert(config.foo is True)
config.foo = False
print(config.foo)
assert(config.foo is False)

config.reload()
print(config.foo)
assert(config.foo is True)

输出:

INIT
<config.Config object at 0x10bbf73d0>
True
False
<config.Config object at 0x10bbf73d0>
True

这工作正常,但我的强迫症无法处理我必须导入配置并执行其主要 class。

我尝试将 sys.modules[__name__] = Config() 添加到 config.py 的底部,这样我就可以只做 import config,但它对 reload() 犹豫不决:

TypeError: 'NoneType' object is not callable

奇怪的是,我只希望它抱怨模块命名空间上的值没有更新,但它似乎事先中断了 - 只是试图执行 reload().

我在这里运气不好吗?或者有什么神奇的方法可以同时使用 reload() 和单行 import config?

当你 reload 时它不起作用的原因是因为在分配给 sys.modules[__name__] 之后,模块及其内置函数被垃圾收集并替换为 None。我假设你知道这一点,因为你 from builtins import *。但是,导入的内置函数也会被垃圾回收。

要解决此问题,您可以在 reload 中导入内置函数,这样您就可以使用不进行垃圾回收的版本。

旁注:这是未经测试的,因为我无法重现您的问题 here,但我相信它会发生,因为该网站在导入时可能会出现问题。