如何让Python方法返回Point数据类集合?解决不可哈希错误
修复TypeError: unhashable type: 'Point'并满足set[Point]返回类型要求
错误原因
Python里集合(set)的元素必须是可哈希类型。默认用@dataclass装饰的类,因为自动生成了__eq__方法,会把__hash__设为None,导致实例不可哈希,没法添加到集合里。
另外你的代码还有几个小问题:
all_points_visited是局部变量,不是实例属性,类方法根本访问不到visited()、visited_count()这些方法缺了self参数,没法获取实例里的数据- 直接修改
self.m的属性,会改动传入的原始Point实例,容易引发意外问题
修复方案
1. 让Point类可哈希
给Point的dataclass装饰器加frozen=True参数,把它变成不可变数据类。这样Python会自动生成合适的__hash__方法,实例就能被添加到集合里了:
from dataclasses import dataclass @dataclass(frozen=True) class Point: x: int y: int z: int
2. 修正Movements类的属性与方法
把all_points_visited改成实例属性,给所有实例方法加上self参数,确保方法能正确访问实例数据:
class Movements: def __init__(self, p: Point): # 新建Point实例,避免修改传入的原始对象 self.m = Point(p.x, p.y, p.z) self.all_points_visited = set() self.all_points_visited.add(self.m) def move_to(self, dir: str) -> None: # 计算新坐标,创建新的Point实例 x, y, z = self.m.x, self.m.y, self.m.z if dir[1] == "x": x += 1 if dir[0] == "+" else -1 elif dir[1] == "y": y += 1 if dir[0] == "+" else -1 elif dir[1] == "z": z += 1 if dir[0] == "+" else -1 self.m = Point(x, y, z) self.all_points_visited.add(self.m) def teleport_to(self, point: Point) -> None: self.m = Point(point.x, point.y, point.z) self.all_points_visited.add(self.m) def visited(self) -> set[Point]: return self.all_points_visited def visited_count(self) -> int: return len(self.all_points_visited)
关于“能否将Point转为元组处理”的问题
如果严格要求visited()必须返回set[Point],那不能用元组存储。因为内部存元组的话,返回的集合类型会是set[tuple[int, int, int]],不符合set[Point]的类型标注,过不了严格的类型检查。就算把元组再转回Point实例返回,也多此一举——直接让Point可哈希是最简洁合规的方案。
测试代码
# 测试 m = Movements(Point(10, -30, 0)) m.move_to("+x") m.teleport_to(Point(5, 5, 5)) print(m.visited_count()) # 输出3 print(m.visited()) # 输出{Point(x=10, y=-30, z=0), Point(x=11, y=-30, z=0), Point(x=5, y=5, z=5)}
内容的提问来源于stack exchange,提问作者Avery
相关产品推荐
相关产品推荐

