Python模块标识为dict

时间:2013-04-19 21:07:09

标签: python

假设我有很多密钥对数据。我想将这些数据放在一个包中,以便可以导入它。出于性能和可扩展性的原因,有没有办法让模块像dicts一样工作?

示例:

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

import BUILDINGS

BUILDINGS["foo"] == "bar"

注意:可以通过在BUILDINGS中声明__init__.py来归档所需的结果,但每次都会编译它们,它不是拖拽和不可饶恕的,而且看起来很难看。

有没有办法做到这一点?有没有办法实现它?

5 个答案:

答案 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的访问,而不仅仅是类似命名空间的访问。

你可以用各种不同的方式把它包起来。

最简单的方法是有效地使用该代码(但使用impglobals,这样您就不会使用中间值污染sys.modulesimport BUILDINGS并放置它在一个函数中,所以不是helper_mod.dict_import(BUILDINGS)而是写DictModuleType

最强大的方法是创建并安装只返回ModuleType而不是__new__的{​​{3}}(您可能需要实施__init__和/或{{例如,对于名称全部为大写的所有模块(只检查是否为fullname.split('.')[-1].isupper(),如果没有,则不包装它)。然后,您可以编写名为BUILDINGS.py的模块,import BUILDINGSBUILDINGS将充当dict