繁体   English   中英

如何使数据类 hash 与字符串相同?

[英]How can I make a dataclass hash the same as a string?

我想用dataclass替换代码中字典中的字符串键,以便我可以为键提供元数据以进行调试。 但是,我仍然希望能够使用字符串来查找字典。 我尝试使用替换的__hash__ function 实现数据类,但是我的代码没有按预期工作:

from dataclasses import dataclass

@dataclass(eq=True, frozen=True)
class Key:
    name: str

    def __hash__(self):
        return hash(self.name)

k = "foo"
foo = Key(name=k)

d = {}
d[foo] = 1

print(d[k])  # Key Error

两个 hash 功能相同:

print(hash(k) == hash(foo))  # True

所以我不明白为什么这不起作用。

具有不同哈希值的两个对象保证它们是不同的,但是具有相同 hash 的两个对象本身并不能保证它们是相同的(因为存在 hash 冲突)。 如果您希望将Key视为等于相应的str ,请在__eq__中实现:

    def __eq__(self, other):
        if isinstance(other, Key):
            return self.name == other.name
        if isinstance(other, str):
            return self.name == other
        return False

这修复了您遇到的KeyError

上面的答案的评论中添加我的笔记,因为在任何情况下都没有人看这些,所以这些很可能在某个时候被扫到地毯下。

  • PyCharm 也会产生一个有用的警告:

    如果 class 已经定义了 ' __eq__ ' 方法,则忽略 'eq'。

    我认为这意味着从@dataclass(...)装饰器中删除eq=True用法。

  • 从技术上讲,您还可以删除最后一个if isinstance(..., str):以及最后一个return语句。 但是,我不完全确定这会产生什么影响。

那么,这里是一种稍微优化的方法(下面带有timeit模块的计时):

class Key:
    name: str

    def __hash__(self):
        return hash(self.name)

    def __eq__(self, other):
        return self.name == getattr(other, 'name', other)

timeit计时

from dataclasses import dataclass
from timeit import timeit


@dataclass(frozen=True)
class Key:
    name: str

    def __hash__(self):
        return hash(self.name)

    def __eq__(self, other):
        if isinstance(other, Key):
            return self.name == other.name
        if isinstance(other, str):
            return self.name == other
        return False


class KeyTwo(Key):
    def __eq__(self, other):
        return self.name == getattr(other, 'name', other)


k = "foo"
foo = Key(name=k)
foo_two = KeyTwo(name=k)

print('__eq__() Timings --')
print('isinstance():  ',  timeit("foo == k", globals=globals()))
print('getattr():     ', timeit("foo_two == k", globals=globals()))

assert foo == foo_two == k

我的M1 Mac上的结果:

__eq__() Timings --
isinstance():   0.10553250007797033
getattr():      0.08371329202782363

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM