如果您真的想要一个可以用作 的模块,则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
.