1

Lets say I have a lot of key-pair data. I would like to have this data in a package so that it can be imported. Is there a way to make modules work like dicts, for performance and extendibility reasons?

Example:

common/pairs/
 ├── BUILDINGS.py
 └── __init__.py

import BUILDINGS

BUILDINGS["foo"] == "bar"

Note: The desired result can be archived by putting declaring BUILDINGS in __init__.py but they will all be compiled every time, its not drag and undroppable, and it seems ugly.

Is there a way to achieve this well? Is there a way to achieve it at all?

4

5 回答 5

2

不是我推荐它,但你可以分配dictinto sys.modules。Python 并不关心实际存在的模块对象。

# BUILDINGS.py
from sys import modules
if __name__ != "__main__":
    modules[__name__] = {'a': 1, 'b': 2, ...}
于 2013-04-19T21:17:02.157 回答
1

模块已经是 dicts,其属性存储在BUILDINGS.__dict__. 只需创建一个实用程序函数即可直接写入它。

于 2013-04-19T21:13:11.280 回答
1

如果我理解正确,我认为您想要的是pickle包裹

IE,

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}
于 2013-04-19T21:13:59.080 回答
0

如果您想存储稍后要引用的键值数据,您应该尝试搁置模块

来自上述链接页面的示例

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.
于 2013-04-19T21:16:36.997 回答
0

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

于 2013-04-19T21:46:17.970 回答