【发布时间】:2012-04-03 16:06:17
【问题描述】:
我需要实现一个可散列的字典,这样我就可以使用一个字典作为另一个字典的键。
几个月前我使用了这个实现:Python hashable dicts
但是,我收到一位同事的通知,说“它并不是真正不可变的,因此它不安全。你可以使用它,但它确实让我觉得自己像一只悲伤的熊猫。
所以我开始四处寻找创建一个不可变的。我不需要将“key-dict”与另一个“key-dict”进行比较。它的唯一用途是作为另一个字典的键。
我想出了以下几点:
class HashableDict(dict):
"""Hashable dict that can be used as a key in other dictionaries"""
def __new__(self, *args, **kwargs):
# create a new local dict, that will be used by the HashableDictBase closure class
immutableDict = dict(*args, **kwargs)
class HashableDictBase(object):
"""Hashable dict that can be used as a key in other dictionaries. This is now immutable"""
def __key(self):
"""Return a tuple of the current keys"""
return tuple((k, immutableDict[k]) for k in sorted(immutableDict))
def __hash__(self):
"""Return a hash of __key"""
return hash(self.__key())
def __eq__(self, other):
"""Compare two __keys"""
return self.__key() == other.__key() # pylint: disable-msg=W0212
def __repr__(self):
"""@see: dict.__repr__"""
return immutableDict.__repr__()
def __str__(self):
"""@see: dict.__str__"""
return immutableDict.__str__()
def __setattr__(self, *args):
raise TypeError("can't modify immutable instance")
__delattr__ = __setattr__
return HashableDictBase()
我使用以下方法来测试功能:
d = {"a" : 1}
a = HashableDict(d)
b = HashableDict({"b" : 2})
print a
d["b"] = 2
print a
c = HashableDict({"a" : 1})
test = {a : "value with a dict as key (key a)",
b : "value with a dict as key (key b)"}
print test[a]
print test[b]
print test[c]
给出:
{'a': 1}
{'a': 1}
以字典为键的值(键 a)
以字典为键的值(键 b)
以 dict 为键的值(键 a)
作为输出
这是我可以使用的满足我要求的“最好的”不可变字典吗?如果没有,有什么更好的解决方案?
【问题讨论】:
-
一个稍微好一点的方法是
tuple(sorted(immutableDict.items()))(或iteritems()pre 3.x)。另外,作为一个注释,我会选择FrozenDict作为默认存在于 Python 中的frozenset类的名称,只是为了命名一致性 - 这并不重要。 -
您的同事可能错过了“同意成人语言”的观点,其中纯 Python 代码中没有任何内容是真正私有的(在强制执行的意义上)。您的代码所做的非常接近于创建不可变对象的预期方式。考虑由 Guido van Rossum、Alex Martelli、Greg Wilson 和我自己编写的 Lib/sets.py 中的 ImmutableSet 代码。标准库代码中的核心开发者代码是否让你的同事“感觉像一只悲伤的熊猫”?
标签: python