Python/Pygame颜色不是元组:作为字典键时出现不可哈希类型错误
背景大致是这样的:
我用Python和Pygame写了一些函数,目的是从一个彩色的小地图创建一个瓷砖式的大地图。在小地图上,每一个像素代表大地图上的一种瓷砖类型。
后来我发现,使用Pygame的surface.get_at((x, y))方法得到的颜色看起来像元组,但其实并不是元组...
这是在一个黑色表面上使用get_at的结果示例:
surf = pygame.Surface((64, 64)).convert()
surf.fill((0, 0, 0))
print(surf.get_at((32, 32))
打印结果:
(0, 0, 0, 255)
所以我想,创建一个以颜色为键的字典应该可以直接这样做:
tiledict = {(0, 0, 0, 255): [tile list 1], (255, 0, 0, 255): [tile list 2], etc}
for y in range(0, tilemap.get_height()):
for x in range(0, tilemap.get_width()):
clr = tilemap.get_at((x, y))
lvlmap.blit(tiledict[clr][random.randint(0, len(tiledict[clr]) - 1)]
结果是:
lvlmap.blit(tiledict[clr][random.randint(0, len(tiledict[clr]) - 1)]
TypeError: unhashable type: 'pygame.Color'
然而,当我在使用这些颜色作为键之前,把它们定义为元组时,这样就可以正常工作了:
GRAY = (128, 128, 128, 255)
print(GRAY == clr)
得到的结果是:
True
我找到了一种解决办法:我把字典的键都设为字符串,然后这样调用get_at:
clr = str(tilemap.get_at((x, y)))
有没有人知道这里面的问题是什么?我觉得这很有意思。颜色不是元组,所以不能被哈希,但当我问它是否等于一个元组时,返回的却是“真”...
我也尝试把所有颜色都定义为元组,这样也能正常工作。但这种方法比我现在的方式慢得多。
有没有人知道我还能尝试什么,而不需要改变类型?
2 个回答
虽然元组和pygame.Color可以用相等运算符比较,但这并不意味着你可以用pygame.Color作为字典的索引。你可能觉得这两者的比较是一样的,但字典的键必须是可哈希的对象。
PyGame.Color
类型特别支持与元组进行比较,前提是这个元组的长度是 3 或 4,并且里面的数字要在 0 到 255 之间(具体可以参考 RGBAFromObj
的源代码)。
这在 PyGame.Color 页面 上有明确的说明:
颜色对象可以与其他颜色对象以及包含 3 或 4 个整数的元组进行相等比较。
任何 Python 类都可以通过实现 __eq__
方法 来定义自定义的相等测试。
这个类型还实现了序列的所有功能,可以返回 R、G、B 和 A 这四个部分;你可以通过调用 tuple()
将 PyGame.Color
转换为元组:
tiledict[tuple(clr)]
然后只需将元组作为单独的参数传入,就可以把它转换回 PyGame.Color
对象:
pygame.Color(*tuple_of_rgba_ints)