【问题标题】:Is there a usecase for overriding __hash__?是否有覆盖 __hash__ 的用例?
【发布时间】:2019-06-25 04:53:07
【问题描述】:

在 Python3 中,任何类都会有一个默认的 __hash__,它会根据成员变量计算哈希值。我可以将它(显式或隐式)设置为 None 以使该类不可散列,这当然有一些用例。

但是有理由覆盖__hash__吗?

我找不到。

【问题讨论】:

  • 我想到的一件事是通过预先计算哈希值并使用 __hash__ 检索这些预先计算的值来加快速度。
  • 如果您的类基于一般不可散列的类型(可能是列表?),但您知道可以以某种独特的方式定义类实例,定义您自己的__hash__ 会让您表达这一点。
  • @AndrejKesely 一些(不是很详细的)测试显示没有可测量的差异。但也许对于需要长时间比较数据的类?那会是什么数据?巨大的字符串?
  • @StephenRauch:还没想过那个。
  • @steffen 是的,我的第一个目标是巨大的字符串。或者,如果您的数据是从网络/数据库动态访问的。或者,如果您的数据采用某种不可散列的数据结构(例如 set(),但 frozenset() 是可散列的)...

标签: python-3.x hash magic-function


【解决方案1】:

是的!任何时候您覆盖__eq__,并且还希望能够将对象用作集合或字典中的键。这在值类型或您的对象代表真实世界实体的情况下尤其常见。

__hash__ 根本不散列成员变量。对于没有定义__hash____eq__ 的对象,它会根据其内部指针返回一些值。如果__eq__ 定义,那么调用该方法将导致TypeError.work

考虑这个简单的情况,默认 __eq____hash__ 行为不是很好:

import getpass

class User:
    def __init__(self, name):
        self.name = name

def currentUser():
   return User(getpass.getuser())

me = currentUser()

passwords = {}
passwords[me] = "sw0rdfish";

这有一些奇怪的行为:me == currentUser() 为假,passwords[currentUser()] 抛出 KeyError。所以为了尝试修复它,我们定义了一个__eq__

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

现在me == currentUser() 为真,但尝试分配密码时会抛出TypeError: unhashable type: 'User'。现在我们已经到了要覆盖__hash__的地步:

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

现在,当您将其用作键时,它的行为就像您期望任何其他此类对象的行为一样。

【讨论】:

    猜你喜欢
    • 2011-03-05
    • 2022-07-31
    • 2020-08-28
    • 2011-06-19
    • 2011-03-28
    • 1970-01-01
    • 1970-01-01
    • 2012-07-01
    • 2016-05-31
    相关资源
    最近更新 更多