我想在单个dict
中使用任何类型的实例作为密钥。
def add_to_dict(my_object, d, arbitrary_val = '123'):
d[ id(my_object) ] = arbitrary_val
d = {}
add_to_dict('my_str', arbitrary_val)
add_to_dict(my_list, arbitrary_val)
add_to_dict(my_int, arbirtray_val)
my_object = myclass()
my_object.__hash__ = None
add_to_dict(my_object, arbitrary_val)
以上不会起作用,因为my_list
和my_object
无法进行哈希处理。
我的第一个想法是使用id
函数传递对象的id()
值。
def add_to_dict(my_object, d, arbitrary_val = '123'):
d[ id(my_object) ] = arbitrary_val
然而,由于id('some string') == id('some string')
不能保证始终为True
,因此无法正常工作。
我的第二个想法是测试对象是否具有__hash__
属性。如果是,请使用该对象,否则,请使用id()
值。
def add_to_dict(my_object, d, arbitrary_val = '123'):
d[ my_object if my_object.__hash__ else id(my_object) ] = arbitrary_val
但是,由于hash()
和id()
都返回int
,我相信我最终会发生冲突。
如何在上面写add_to_dict(obj, d)
以确保无论obj
是什么list
,int
,str
,object
, dict
),它会正确设置字典中的项目而不会发生冲突吗?
答案 0 :(得分:1)
我们可以创建一些允许我们插入可变对象的字典:
class DictionaryMutable:
nullobject = object()
def __init__(self):
self._inner_dic = {}
self._inner_list = []
def __getitem__(self, name):
try:
return self._inner_dic[name]
except TypeError:
for key, val in self._inner_list:
if name == key:
return val
raise KeyError(name)
def __setitem__(self, name, value):
try:
self._inner_dic[name] = value
except TypeError:
for elm in self._inner_list:
if name == elm[0]:
elm[1] = value
break
else:
self._inner_list.append([name,value])
# ...
其工作原理如下:DictionaryMutable
由字典和列表组成。该字典包含可散列的不可变键,该列表包含子列表,其中每个子列表包含两个元素:键和值。
对于每次查找,我们首先尝试对字典执行查找,如果密钥name
不可删除,则会抛出TypeError
。在这种情况下,我们遍历列表,检查其中一个键是否匹配,如果匹配则返回相应的值。如果不存在此类元素,我们会引发KeyError
。
设置元素的工作方式大致相同:首先我们尝试在字典中设置元素。如果事实证明密钥是不可用的,我们在列表中线性搜索并且旨在添加元素。如果失败,我们将其添加到列表的末尾。
这种实现有一些主要的缺点:
这只是一个基本的实现。例如,__iter__
等也需要实施。
答案 1 :(得分:1)
您可以使用对象pickle.dumps()
的pickle字节流表示而不是对象的id()
。 pickle
适用于大多数内置类型,并且有一些方法可以扩展它以使用大多数值,它不知道如何自动执行。
注意:我使用对象的repr()
作为其“任意值”,以便更容易在显示的输出中识别它们。
try:
import cpickle as pickle
except ModuleNotFoundError:
import pickle
from pprint import pprint
def add_to_dict(d, obj, arbitrary_val='123'):
d[pickle.dumps(obj)] = arbitrary_val
class MyClass: pass
my_string = 'spam'
my_list = [13, 'a']
my_int = 42
my_instance = MyClass()
d = {}
add_to_dict(d, my_string, repr(my_string))
add_to_dict(d, my_list, repr(my_list))
add_to_dict(d, my_int, repr(my_int))
add_to_dict(d, my_instance, repr(my_instance))
pprint(d)
输出:
{b'\x80\x03K*.': '42',
b'\x80\x03X\x04\x00\x00\x00spamq\x00.': "'spam'",
b'\x80\x03]q\x00(K\rX\x01\x00\x00\x00aq\x01e.': "[13, 'a']",
b'\x80\x03c__main__\nMyClass\nq\x00)\x81q\x01.': '<__main__.MyClass object at '
'0x021C1630>'}