Python/Pygame颜色不是元组:作为字典键时出现不可哈希类型错误

1 投票
2 回答
866 浏览
提问于 2025-04-18 07:08

背景大致是这样的:

我用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 个回答

2

虽然元组和pygame.Color可以用相等运算符比较,但这并不意味着你可以用pygame.Color作为字典的索引。你可能觉得这两者的比较是一样的,但字典的键必须是可哈希的对象。

2

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)

撰写回答