Python不允许将字典用作其他字典中的键。是否有解决方法可以使用非嵌套字典作为键?
对于更复杂的非可哈希对象的一般问题以及我的具体用例已经移至此处。我最初对用例的描述是错误的。
Python不允许将字典用作其他字典中的键。是否有解决方法可以使用非嵌套字典作为键?
对于更复杂的非可哈希对象的一般问题以及我的具体用例已经移至此处。我最初对用例的描述是错误的。
[('content-type','text/plain'),('host','example.com')]
),那么你可以将你的dict
转换为:
一对元组。在你的问题中已经这样做了。必须使用tuple
而不是list
,因为结果依赖于元素的排序和不可变性。
>>> tuple(sorted(a.items()))
一个冻结集合。从数学角度来看,这是一种更适合的方法,因为它仅需要对您的不可变dict
元素使用相等关系,而第一种方法除了相等性还需要排序关系。
>>> frozenset(a.items())
tuple(someDictionary.items())
非常完美地将字典转化为不可变键。 - S.Lottsomedictionary.items()
排序后转为元组(tuple),因为字典的键值顺序未被保证,这意味着相等的字典可能通过按不同顺序列出其条目来产生不同的表示形式。 - Brian.items()
。 - Denis Otkidachkey = tuple(sorted(someDictionary .items())
dict( key )
轻松地实现反转。frozenset
更加“正确”,请看我的答案。 - Andrey Vlasovskikhtuple(sorted())
就可以工作。frozenset
需要具有可哈希性的字典值。 - BallpointBen一种方法是通过子类化字典并提供哈希方法来实现。例如:
class HashableDict(dict):
def __hash__(self):
return hash(tuple(sorted(self.iteritems())))
>>> d = HashableDict(a=1, b=2)
>>> d2 = { d : "foo"}
>>> d2[HashableDict(a=1, b=2)]
"foo"
需要注意的是,字典(或任何可变类型)不这样做的原因:在将对象添加到哈希表之后对其进行更改会更改哈希值,这意味着字典现在会将它放入错误的桶中,因此将返回不正确的结果。
如果您选择这种方式,请确保非常确定字典在放入其他字典后永远不会发生更改,或者积极地防止它们发生更改(例如,检查哈希值在第一次调用__hash__
之后是否更改,并在不更改时抛出异常)。
嗯,你的使用场景难道不只是记忆函数调用吗?使用装饰器,您将轻松支持任意函数。是的,它们经常pickle参数,并使用循环推理,只要它们可以被pickled,这对于非标准类型也有效。
例如,请参见此记忆化示例
import json
Dict = {'key' :'value123'}
stringifiedDict = json.dumps(Dict)
print(stringifiedDict)
# {"key": "value123"}
newDict = {stringifiedDict: 12345}
print(newDict[stringifiedDict])
# 12345
for key, val in newDict.items():
print(json.loads(key))
# {'key': 'value123'}
print(json.loads(key)['key'])
# value123
类名…OK :/
我的解决方案是创建一个类,具有字典功能,但实现为一个包含{key, value}
对象的列表。key和value可以是任何内容。
class DictKeyDictException(Exception):
pass
class DictKeyDict():
def __init__(self, *args):
values = [self.__create_element(key, value) for key, value in args]
self.__values__ = values
def __setitem__(self, key, value):
self.set(key, value)
def __getitem__(self, key):
return self.get(key)
def __len__(self):
return len(self.__values__)
def __delitem__(self, key):
keys = self.keys()
if key in keys:
index = keys.index(key)
del self.__values__[index]
def clear(self):
self.__values__ = []
def copy(self):
return self.__values__.copy()
def has_key(self, k):
return k in self.keys()
def update(self, *args, **kwargs):
if kwargs:
raise DictKeyDictException(f"no kwargs allowed in '{self.__class__.__name__}.update' method")
for key, value in args:
self[key] = value
return self.__values__
def __repr__(self) -> list:
return repr(self.__values__)
@classmethod
def __create_element(cls, key, value):
return {"key": key, "value": value}
def set(self, key, value) -> None:
keys = self.keys()
if key in keys:
index = keys.index(key)
self.__values__[index] = self.__create_element(key, value)
else:
self.__values__.append(self.__create_element(key, value))
return self.__values__
def keys(self):
return [dict_key_value["key"] for dict_key_value in self.__values__]
def values(self):
return [value["value"] for value in self.__values__]
def items(self):
return [(dict_key_value["key"], dict_key_value["value"]) for dict_key_value in self.__values__]
def pop(self, key, default=None):
keys = self.keys()
if key in keys:
index = keys.index(key)
value = self.__values__.pop(index)["value"]
else:
value = default
return value
def get(self, key, default=None):
keys = self.keys()
if key in keys:
index = keys.index(key)
value = self.__values__[index]["value"]
else:
value = default
return value
def __iter__(self):
return iter(self.keys())
和用法:
dad = {"name": "dad"}
mom = {"name": "mom"}
boy = {"name": "son"}
girl = {"name": "daughter"}
# set
family = DictKeyDict()
family[dad] = {"age": 44}
family[mom] = {"age": 43}
# or
family.set(dad, {"age": 44, "children": [boy, girl]})
# or
family = DictKeyDict(
(dad, {"age": 44, "children": [boy, girl]}),
(mom, {"age": 43, "children": [boy, girl]}),
)
# update
family.update((mom, {"age": 33})) # oups sorry miss /!\ loose my children
family.set({"pet": "cutty"}, "cat")
del family[{"pet": "cutty"}] # cutty left...
family.set({"pet": "buddy"}, "dog")
family[{"pet": "buddy"}] = "wolf" # buddy was not a dog
print(family.keys())
print(family.values())
for k, v in family.items():
print(k, v)
我不明白为什么你会想这样做,但如果你确实需要,你可以尝试将字典进行序列化(pickling):
mydict = {"a":1, "b":{"c":10}}
import pickle
key = pickle.dumps(mydict)
d[key] = value
这个函数将把一个嵌套的字典转换成一个不可变的元组,你可以把它作为一个键来使用:
def convert_dictionary_tuple(input_dict):
"""
this function receives a nested dictionary and convert it to an immutable tuple of tuples with all the given
dictionary data
:param input_dict: a nested dictionary
:return: immutable tuple of tuples with all the given dictionary data
"""
tuples_dict = {}
for key, value in input_dict.iteritems():
if isinstance(value, dict):
tuples_dict[key] = convert_dictionary_tuple(value)
elif isinstance(value, list):
tuples_dict[key] = tuple([convert_dictionary_tuple(v) if isinstance(v, dict) else v for v in value])
else:
tuples_dict[key] = value
return tuple(sorted(tuples_dict.items()))
我不确定我是否正确理解了你的问题,但我会尝试回答
d[repr(a)]=value
for el1 in d:
for el2 in eval(el1):
print el2,eval(el1)[el2]
repr
和str
实际上是相同的。然而,这种方式可能会遇到问题 - 可能会得到具有不同内部状态的字典,尽管它们包含相同的项,但按不同的顺序列出其键,因此会产生不同的键。如果在字典中存储没有属性使得repr(x)== repr(y)<=> x == y
的对象(例如大多数用户创建的类),也会遇到问题。 - Briantuple( someDictionary.items() )
替代 repr
。这样可以得到一个结构,可以很容易地转换回字典,而无需使用 eval
。 - S.Lott
sorted
,它返回一个生成器,所以你需要将其转换为list
。 - Andrey Vlasovskikh