python - python可变和可散列类型
解决方案
下面是一些代码,向您展示了使对象既可哈希又可变的效果。请注意,您提供的链接确实在 Andrew Jaffe 的答案及其下方的评论中回答了您的问题;为了帮助解释,我从这个问题中添加了一些关于散列的代码。
python 对象的哈希值的默认值是对象 ID,在其生命周期内不会更改。自定义值可以由__hash__
; 然而,为了有用,它必须被翻译成可以散列的东西,比如整数或字符串。
class test():
use_int = 0
use_name = ""
use_list = []
def __init__(self, use_int:int, use_name:str, use_list:list)->None:
self.use_int = use_int
self.use_name = use_name
self.use_list = use_list
# Compact the attributes into a tuple of int and strings
# Without changing the list into a string, the hash will fail
def __key(self):
return (str(self.use_int), self.use_name,",".join(self.use_list))
# The above step could be done here with a small object like this
def __hash__(self):
return hash(self.__key())
# For fun: try changing this to "__repr__"
def __str__(self):
return ",".join(self.__key())
让我们运行一下,看看结果是什么:
if __name__ == "__main__":
# Initialise our object
test_obj = test(0,"John",["test","more test",])
任何时候我们想查看哈希值,我们都可以使用print(test_obj.__hash__())
. 尝试更改int
并查看哈希是否更改。此外,由于 Python 使用带有 str 散列的随机盐来防止冲突,还要注意这种散列方式将在不同的进程中提供不同的散列值。
我们可以通过测试字典是否接受该对象作为键来证明该对象可用作可散列对象。例如,字典键不能是列表。
test_dict = dict()
test_dict[test_obj] = "first object used as key"
print(test_dict)
尝试更改对象中的列表,看看它是否仍然可以接受:
test_obj.use_list.append("yet more tests")
test_dict[test_obj] = "second object used as key"
print(test_dict)
如果我们需要回去怎么办?
del test_obj.use_list[-1]
test_dict[test_obj] = "third object used as key"
print(test_dict)
请注意“第一个对象”如何更改为“第三个对象”。
将所有这些代码放在一起:
class test():
use_int = 0
use_name = ""
use_list = []
def __init__(self, use_int:int, use_name:str, use_list:list)->None:
self.use_int = use_int
self.use_name = use_name
self.use_list = use_list
def __key(self):
return (str(self.use_int), self.use_name,",".join(self.use_list))
def __hash__(self):
return hash(self.__key())
def __str__(self):
return ",".join(self.__key())
if __name__ == "__main__":
test_obj = test(0,"John",["test","more test",])
print(test_obj.__hash__())
test_obj.use_int = 1
print(test_obj.__hash__())
test_obj.use_int = 2
print(test_obj.__hash__())
test_dict = dict()
test_dict[test_obj] = "object used as key"
print(test_dict)
test_obj.use_list.append("yet more tests")
test_dict[test_obj] = "second object"
print(test_dict)
del test_obj.use_list[-1]
test_dict[test_obj] = "third object"
print(test_dict)
print(test_obj)
test_obj.use_int = 1
print(test_obj.__hash__())
但是如果我们需要一个一致的、可预测的哈希值呢?__hash()
不必使用hash()
!它可以返回其他值。这将意味着使过程兼容 - 否则你会得到TypeError: __hash__ method should return an integer
.
尝试将名称转换为整数:
def __key(self):
name_number = 0
for c in self.use_name:
name_number += ord(c)
return self.use_int + name_number
def __hash__(self):
return self.__key()
def __str__(self):
return str(self.__key())
如果在这种情况下运行字典测试会发生什么?
您会注意到,字典中没有两个条目,而是只有一个 - 这是因为更改列表不会更改对象产生的哈希值。
原始随机哈希字典测试的结果:
{< main .test object at 0x7f05bc1f1fd0>: 'first object'}
{< main .test object at 0x7f05bc1f1fd0>: 'object used as key', < main .test object at 0x7f05bc1f1fd0>: 'second object'}
{< main . 0x7f05bc1f1fd0> 处的测试对象:'第三个对象',< 0x7f05bc1f1fd0 处的主.test 对象>:'第二个对象'}
第二次固定哈希字典测试的结果:
{< main .test object at 0x7fc7b5510fd0>: 'first object'}
{< main .test object at 0x7fc7b5510fd0>: 'second object'}
{< main .test object at 0x7fc7b5510fd0>: '第三个 object'}
推荐阅读
- c# - Microsoft 是否有任何用于 Razor 视图和 Razor 页面的官方测试工具?
- python - 将 3d 坐标拟合成抛物线
- java - 异常处理执行流程
- python - 将包含文件的文件夹上传到 FTP 服务器 Python 时出现问题
- sharepoint - PowerApps - 库过滤多行文本输入中的所有值 - 委派错误
- php - 使用 SSE 轮询数据库的最有效方法
- git - 共享 .git 文件夹(有目的地)以发送所有本地工作
- android - Godot,为什么我的 android 导出找不到/打开文件?
- python - 如何使用请求访问 python 中的开发者控制台?
- typescript - 键入'字符串 | number' 不可分配给类型 'ReturnType
'