假设我有很多密钥对数据。我想将这些数据放在一个包中,以便可以导入它。出于性能和可扩展性的原因,有没有办法让模块像dicts一样工作?
示例:
common/pairs/
├── BUILDINGS.py
└── __init__.py
import BUILDINGS
BUILDINGS["foo"] == "bar"
注意:可以通过在BUILDINGS
中声明__init__.py
来归档所需的结果,但每次都会编译它们,它不是拖拽和不可饶恕的,而且看起来很难看。
有没有办法做到这一点?有没有办法实现它?
答案 0 :(得分:2)
不是我推荐的,但您可以将dict
分配到sys.modules
。 Python并不关心实际上是什么模块对象。
# BUILDINGS.py
from sys import modules
if __name__ != "__main__":
modules[__name__] = {'a': 1, 'b': 2, ...}
答案 1 :(得分:1)
模块已经将其属性存储在BUILDINGS.__dict__
中。只需将实用程序功能直接写入即可。
答案 2 :(得分:1)
如果我理解正确,我认为你想要的是pickle
包
即
In [16]: import pickle
In [17]: mydict = {'this':1, 'is':2, 'my':3, 'dict':4}
In [18]: mydict
Out[18]: {'dict': 4, 'is': 2, 'my': 3, 'this': 1}
In [20]: outfile = open('/tmp/mydict.pickle', 'w')
In [21]: pickle.dump(mydict, outfile)
In [22]: outfile.close()
In [23]: infile = open('/tmp/mydict.pickle', 'r')
In [24]: mydict_loaded = pickle.load(infile)
In [25]: mydict_loaded
Out[25]: {'dict': 4, 'is': 2, 'my': 3, 'this': 1}
答案 3 :(得分:0)
如果要存储以后要引用的键值数据,应该尝试shelve模块
上述链接页面的示例
import shelve
d = shelve.open(filename) # open -- file may get suffix added by low-level
# library
d[key] = data # store data at key (overwrites old data if
# using an existing key)
data = d[key] # retrieve a COPY of data at key (raise KeyError if no
# such key)
del d[key] # delete data stored at key (raises KeyError
# if no such key)
flag = d.has_key(key) # true if the key exists
klist = d.keys() # a list of all existing keys (slow!)
# as d was opened WITHOUT writeback=True, beware:
d['xx'] = range(4) # this works as expected, but...
d['xx'].append(5) # *this doesn't!* -- d['xx'] is STILL range(4)!
# having opened d without writeback=True, you need to code carefully:
temp = d['xx'] # extracts the copy
temp.append(5) # mutates the copy
d['xx'] = temp # stores the copy right back, to persist it
# or, d=shelve.open(filename,writeback=True) would let you just code
# d['xx'].append(5) and have it work as expected, BUT it would also
# consume more memory and make the d.close() operation slower.
答案 4 :(得分:0)
如果确实想要一个可用作dict
的模块,则必须使其实现映射协议。
特别是,您需要确保type(BUILDINGS).__getitem__(BUILDINGS, key)
已定义(例如getattr(BUILDINGS, key)
。同样适用于__setitem__
,__delitem__
以及您想要的任何其他内容实施。(如果您使用的是collections.abc.MutableMapping
,则可以获得所需的大部分内容;如果您使用的是collections.MutableMapping
,则可以module
。请参阅the docs了解您必须实施的内容以获取所有内容别的免费。)
问题在于(至少在CPython中,这可能是你关心的)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__
,就像真正的模块一样,除了它还提供类似dict的访问,而不仅仅是类似命名空间的访问。
你可以用各种不同的方式把它包起来。
最简单的方法是有效地使用该代码(但使用imp
或globals
,这样您就不会使用中间值污染sys.modules
和import BUILDINGS
并放置它在一个函数中,所以不是helper_mod.dict_import(BUILDINGS)
而是写DictModuleType
。
最强大的方法是创建并安装只返回ModuleType
而不是__new__
的{{3}}(您可能需要实施__init__
和/或{{例如,对于名称全部为大写的所有模块(只检查是否为fullname.split('.')[-1].isupper()
,如果没有,则不包装它)。然后,您可以编写名为BUILDINGS.py
的模块,import BUILDINGS
和BUILDINGS
将充当dict
。