如果您真的想要一个可以用作 的模块,则dict必须使其实现映射协议。
特别是,您需要确保type(BUILDINGS).__getitem__(BUILDINGS, key)已定义(例如getattr(BUILDINGS, key). 以及__setitem__,__delitem__以及您想要实现的任何其他内容。(您可以通过 获得大部分想要的内容collections.abc.MutableMapping,或者collections.MutableMapping如果您使用的是 2.x 。请参阅文档,了解您必须实施什么才能免费获得其他所有内容。)
问题是(至少在 CPython 中,这可能是您关心的)module是一个无法修改属性的内置类型。所以,你需要BUILDINGS成为一个不同类型的实例,然后你可以添加__getitem__它。例如:
class DictModuleType(types.ModuleType, collections.abc.MutableMapping):
def __getitem__(self, key):
return getattr(self, key)
def __setitem__(self, key, value):
return setattr(self, key, value)
# ... etc.
import BUILDINGS as _BUILDINGS
BUILDINGS = DictModuleType('BUILDINGS')
for name, member in inspect.getmembers(_BUILDINGS):
if not name.startswith('_'):
setattr(BUILDINGS, name, member)
现在你有了一个BUILDINGS和真正的模块一样的行为,除了它还提供类似字典的访问,而不仅仅是类似命名空间的访问。
你可以用各种不同的方式把它包起来。
最简单的方法是有效地利用该代码(但使用__import__orimp这样你就不会污染globals并且sys.modules使用中间值)并将它放在一个函数中,而不是import BUILDINGS你写helper_mod.dict_import(BUILDINGS).
最强大的方法是创建并安装一个导入钩子,它只返回一个DictModuleType而不是ModuleType(您可能需要实现__new__和/或__init__使其工作),例如,所有名称全部大写的模块(只需检查 iffullname.split('.')[-1].isupper()和,如果没有,请不要包装它)。然后,您可以编写一个名为BUILDINGS.py, 和import BUILDINGS,的模块,BUILDINGS其行为类似于dict.