冻结集就是冻结集。 冻结列表可以是元组。 冷冻字典会是什么?一个不可变的、可哈希的字典。
我猜它可能是collections.namedtuple之类的东西,但那更像是一个冻结的字典(一个半冻结的字典)。不是吗?
一个“frozendict”应该是一个冻结的字典,它应该有键,值,get等,并支持in, for等。
更新: 在这里:https://www.python.org/dev/peps/pep-0603
冻结集就是冻结集。 冻结列表可以是元组。 冷冻字典会是什么?一个不可变的、可哈希的字典。
我猜它可能是collections.namedtuple之类的东西,但那更像是一个冻结的字典(一个半冻结的字典)。不是吗?
一个“frozendict”应该是一个冻结的字典,它应该有键,值,get等,并支持in, for等。
更新: 在这里:https://www.python.org/dev/peps/pep-0603
当前回答
是的,这是我的第二个答案,但这是一个完全不同的方法。第一个实现是用纯python实现的。这是Cython的。如果您知道如何使用和编译Cython模块,这与使用常规字典一样快。大约0.04到0.06微秒来检索一个值。
这是frozen_dict。pyx文件
import cython
from collections import Mapping
cdef class dict_wrapper:
cdef object d
cdef int h
def __init__(self, *args, **kw):
self.d = dict(*args, **kw)
self.h = -1
def __len__(self):
return len(self.d)
def __iter__(self):
return iter(self.d)
def __getitem__(self, key):
return self.d[key]
def __hash__(self):
if self.h == -1:
self.h = hash(frozenset(self.d.iteritems()))
return self.h
class FrozenDict(dict_wrapper, Mapping):
def __repr__(self):
c = type(self).__name__
r = ', '.join('%r: %r' % (k,self[k]) for k in self)
return '%s({%s})' % (c, r)
__all__ = ['FrozenDict']
这是setup。py文件
from distutils.core import setup
from Cython.Build import cythonize
setup(
ext_modules = cythonize('frozen_dict.pyx')
)
如果安装了Cython,请将上述两个文件保存到同一目录中。在命令行中移动到该目录。
python setup.py build_ext --inplace
python setup.py install
你应该做完了。
其他回答
是的,这是我的第二个答案,但这是一个完全不同的方法。第一个实现是用纯python实现的。这是Cython的。如果您知道如何使用和编译Cython模块,这与使用常规字典一样快。大约0.04到0.06微秒来检索一个值。
这是frozen_dict。pyx文件
import cython
from collections import Mapping
cdef class dict_wrapper:
cdef object d
cdef int h
def __init__(self, *args, **kw):
self.d = dict(*args, **kw)
self.h = -1
def __len__(self):
return len(self.d)
def __iter__(self):
return iter(self.d)
def __getitem__(self, key):
return self.d[key]
def __hash__(self):
if self.h == -1:
self.h = hash(frozenset(self.d.iteritems()))
return self.h
class FrozenDict(dict_wrapper, Mapping):
def __repr__(self):
c = type(self).__name__
r = ', '.join('%r: %r' % (k,self[k]) for k in self)
return '%s({%s})' % (c, r)
__all__ = ['FrozenDict']
这是setup。py文件
from distutils.core import setup
from Cython.Build import cythonize
setup(
ext_modules = cythonize('frozen_dict.pyx')
)
如果安装了Cython,请将上述两个文件保存到同一目录中。在命令行中移动到该目录。
python setup.py build_ext --inplace
python setup.py install
你应该做完了。
假设字典的键和值本身是不可变的(例如字符串),那么:
>>> d
{'forever': 'atones', 'minks': 'cards', 'overhands': 'warranted',
'hardhearted': 'tartly', 'gradations': 'snorkeled'}
>>> t = tuple((k, d[k]) for k in sorted(d.keys()))
>>> hash(t)
1524953596
奇怪的是,尽管我们有很少有用的frozenset,但仍然没有冻结映射。这个想法在PEP 416中被否决了——添加一个frozendict内置类型。这个想法可能会在后面的Python版本中重新讨论,请参阅PEP 603—向集合添加frozenmap类型。
所以Python 2的解决方案是:
def foo(config={'a': 1}):
...
这似乎仍是常态:
def foo(config=None):
if config is None:
config = {'a': 1} # default config
...
在Python 3中,你可以这样做:
from types import MappingProxyType
default_config = {'a': 1}
DEFAULTS = MappingProxyType(default_config)
def foo(config=DEFAULTS):
...
现在,默认配置可以动态更新,但在您希望它不可变的地方保持不变,只需传递代理即可。
因此,default_config中的更改将按预期更新默认值,但不能写入映射代理对象本身。
诚然,它与“不可变的、可哈希的字典”不是一回事,但它可能是frozendict某些用例的体面替代品。
在没有本地语言支持的情况下,您可以自己动手,也可以使用现有的解决方案。幸运的是,Python使得扩展它们的基本实现变得非常简单。
class frozen_dict(dict):
def __setitem__(self, key, value):
raise Exception('Frozen dictionaries cannot be mutated')
frozen_dict = frozen_dict({'foo': 'FOO' })
print(frozen['foo']) # FOO
frozen['foo'] = 'NEWFOO' # Exception: Frozen dictionaries cannot be mutated
# OR
from types import MappingProxyType
frozen_dict = MappingProxyType({'foo': 'FOO'})
print(frozen_dict['foo']) # FOO
frozen_dict['foo'] = 'NEWFOO' # TypeError: 'mappingproxy' object does not support item assignment
没有fronzedict,但你可以使用MappingProxyType,它被添加到Python 3.3的标准库中:
>>> from types import MappingProxyType
>>> foo = MappingProxyType({'a': 1})
>>> foo
mappingproxy({'a': 1})
>>> foo['a'] = 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'mappingproxy' object does not support item assignment
>>> foo
mappingproxy({'a': 1})