是什么让用户定义的课程富有植物? -- python 领域 和 class 领域 和 python-3.x 领域 和 user-defined-types 领域 和 hashable 领域 相关 的问题

What makes a user-defined class unhashable?


46
vote

问题

中文

docs 只要它是哈希可占据定义 __hash__ 方法和 __eq__ 方法。但是:

  class X(list):   # read-only interface of `tuple` and `list` should be the same, so reuse tuple.__hash__   __hash__ = tuple.__hash__  x1 = X() s = {x1} # TypeError: unhashable type: 'X'   

是什么让 X 富有植物?

请注意,我必须具有相同的列表(根据常规平等)散列到相同的值;否则,我将违反此要求哈希功能:

唯一必需的属性是比较相等的对象 相同的哈希值

文档确实警告在其使用寿命期间不应修改哈希可将对象,当然我不会在创建后修改 var ent1 = new string[20]; for (int i = 0; i < ent1.Count; i++) { var entKey = "Entities1[" + i.ToString() + "]"; var acct = Request.Form[entKey]; if (!string.IsNullOrEmpty(acct)) { ent1[i] = acct; } else { break; } } 0 的实例。当然,解释器无论如何都不会检查。

英文原文

The docs say that a class is hashable as long as it defines __hash__ method and __eq__ method. However:

class X(list):   # read-only interface of `tuple` and `list` should be the same, so reuse tuple.__hash__   __hash__ = tuple.__hash__  x1 = X() s = {x1} # TypeError: unhashable type: 'X' 

What makes X unhashable?

Note that I must have identical lists (in terms of regular equality) to be hashed to the same value; otherwise, I will violate this requirement on hash functions:

The only required property is that objects which compare equal have the same hash value

The docs do warn that a hashable object shouldn't be modified during its lifetime, and of course I don't modify instances of X after creation. Of course, the interpreter won't check that anyway.

              
   
   

回答列表

29
 
vote
vote
最佳答案
 

简单地将 Row1 方法设置为 Row2 类是不够的。你实际上没有告诉过它如何以不同的方式哈希。元组是哈希可行的,因为它们是不可变的。如果您真的想使您具体的示例工作,可能是这样的:

  Row3  

在这种情况下,您实际上是定义如何散列您的自定义列表子类。您只需定义它如何生成哈希。您可以哈希讨论您想要的任何内容,而不是使用元组的散列方法:

  Row4  
 

Simply setting the __hash__ method to that of the tuple class is not enough. You haven't actually told it how to hash any differently. tuples are hashable because they are immutable. If you really wanted to make you specific example work, it might be like this:

class X2(list):     def __hash__(self):         return hash(tuple(self)) 

In this case you are actually defining how to hash your custom list subclass. You just have to define exactly how it can generate a hash. You can hash on whatever you want, as opposed to using the tuple's hashing method:

def __hash__(self):     return hash("foobar"*len(self)) 
 
 
       
       
20
 
vote

从Python3文档:

如果一个类没有定义__eq __()方法,它不应该定义一个 __hash __()操作;如果它定义__eq __()但不是__hash __(),它的实例将不可用作哈希可集合中的项目。如果类定义可变对象并实现一个 __eq __()方法,它不应该实现__hash __(),因为哈希可集合的实施要求一个关键的哈希 价值是不可变的(如果对象的哈希值改变,它将进入 错误的哈希桶)。

ref:对象._哈希__(self)

示例代码:

  Row5  
 

From the Python3 docs:

If a class does not define an __eq__() method it should not define a __hash__() operation either; if it defines __eq__() but not __hash__(), its instances will not be usable as items in hashable collections. If a class defines mutable objects and implements an __eq__() method, it should not implement __hash__(), since the implementation of hashable collections requires that a keyxe2x80x99s hash value is immutable (if the objectxe2x80x99s hash value changes, it will be in the wrong hash bucket).

Ref: object.__hash__(self)

Sample code:

class Hashable:     pass  class Unhashable:     def __eq__(self, other):         return (self == other)  class HashableAgain:     def __eq__(self, other):         return (self == other)      def __hash__(self):         return id(self)  def main():     # OK     print(hash(Hashable()))     # Throws: TypeError("unhashable type: 'X'",)     print(hash(Unhashable()))       # OK     print(hash(HashableAgain())) 
 
 
   
   
6
 
vote

您可以并应根据您的其他问题做什么,是: 不要子类,只需封装元组。在init中这样做是完全没事的。

  Row6  

哪种产量:

  Row7  
 

What you could and should do, based on your other question, is: don't subclass anything, just encapsulate a tuple. It's perfectly fine to do so in the init.

class X(object):     def __init__(self, *args):         self.tpl = args     def __hash__(self):         return hash(self.tpl)     def __eq__(self, other):         return self.tpl == other     def __repr__(self):         return repr(self.tpl)  x1 = X() s = {x1} 

which yields:

>>> s set([()]) >>> x1 () 
 
 
 
 
3
 
vote

如果在创建之后不要修改 998876660 的实例,为什么您不是子类化元组?

但是我将指出,这实际上不会抛出错误,至少在Python 2.6中。

  >>> class X(list): ...     __hash__ = tuple.__hash__ ...     __eq__ = tuple.__eq__ ...  >>> x = X() >>> s = set((x,)) >>> s set([[]])   

我犹豫了说"Works" ,因为这不做你的想法。

  >>> a = X() >>> b = X((5,)) >>> hash(a) 4299954584 >>> hash(b) 4299954672 >>> id(a) 4299954584 >>> id(b) 4299954672   

它只是使用对象ID作为哈希。当您实际调用<代码> __hash__ 时,您仍然会出错;同样用于 __eq__

  >>> a.__hash__() Traceback (most recent call last):   File "<stdin>", line 1, in <module> TypeError: descriptor '__hash__' for 'tuple' objects doesn't apply to 'X' object >>> X().__eq__(X()) Traceback (most recent call last):   File "<stdin>", line 1, in <module> TypeError: descriptor '__eq__' for 'tuple' objects doesn't apply to 'X' object   

我收集了Python内部,出于某种原因,检测到 99887666 具有 __hash__ __eq__ 方法,但aren' t叫他们。

所有这一切的寓意是:只写一个真正的哈希函数。由于这是一个序列对象,将其转换为元组和散列,这是最明显的方法。

  def __hash__(self):     return hash(tuple(self))   
 

If you don't modify instances of X after creation, why aren't you subclassing tuple?

But I'll point out that this actually doesn't throw an error, at least in Python 2.6.

>>> class X(list): ...     __hash__ = tuple.__hash__ ...     __eq__ = tuple.__eq__ ...  >>> x = X() >>> s = set((x,)) >>> s set([[]]) 

I hesitate to say "works" because this doesn't do what you think it does.

>>> a = X() >>> b = X((5,)) >>> hash(a) 4299954584 >>> hash(b) 4299954672 >>> id(a) 4299954584 >>> id(b) 4299954672 

It's just using the object id as a hash. When you actually call __hash__ you still get an error; likewise for __eq__.

>>> a.__hash__() Traceback (most recent call last):   File "<stdin>", line 1, in <module> TypeError: descriptor '__hash__' for 'tuple' objects doesn't apply to 'X' object >>> X().__eq__(X()) Traceback (most recent call last):   File "<stdin>", line 1, in <module> TypeError: descriptor '__eq__' for 'tuple' objects doesn't apply to 'X' object 

I gather that the python internals, for some reason, are detecting that X has a __hash__ and an __eq__ method, but aren't calling them.

The moral of all this is: just write a real hash function. Since this is a sequence object, converting it to a tuple and hashing that is the most obvious approach.

def __hash__(self):     return hash(tuple(self)) 
 
 
         
         
1
 
vote

上述答案的添加 - 对于Python3.7 +中的DataClass的特定情况 - 要使DataClass Hashable,可以使用

  >>> class X(list): ...     __hash__ = tuple.__hash__ ...     __eq__ = tuple.__eq__ ...  >>> x = X() >>> s = set((x,)) >>> s set([[]]) 0  

作为装饰而不是

  >>> class X(list): ...     __hash__ = tuple.__hash__ ...     __eq__ = tuple.__eq__ ...  >>> x = X() >>> s = set((x,)) >>> s set([[]]) 1  
 

An addition to the above answers - For the specific case of a dataclass in python3.7+ - to make a dataclass hashable, you can use

@dataclass(frozen=True) class YourClass:     pass 

as the decoration instead of

@dataclass class YourClass:     pass 
 
 

相关问题

9  在Python中线性拟合,在x和y坐标中具有不确定性[关闭]  ( Linear fitting in python with uncertainty in both x and y coordinates ) 
关闭。这个问题不符合堆栈溢出指南。它目前不接受答案。 想要改进这个问题?更新问题,所以它是关于堆栈溢出的主题。 closed 1年前。 ...

0  腌制物体的大小wrt gae blobproperty  ( Size of pickled object wrt gae blobproperty ) 
我正在挑痒一个python dictonary,并将它存储到gae blobproperty。 blobproperty有一个 1mb大小限制。我想以编程方式检查我的对象将在1MB限制中'fit'。 var_dump($ECB_rates); 5 但是len(pickled_object)测量是什么? (字符...

0  有没有办法从IEX获取实时数据?  ( Is there a way to get real time data from iex ) 
我刚刚学会使用 iex-cloud-api 但是当我打印出结果时,我一天只得到它们。我想在一分钟内得到它们。我的代码基本上如下所示: start = datetime.date(2020, 12, 20) df = get_historical_data(stocksymbol, ...

0  将一个3D坐标系旋转到另一个  ( Rotate one 3d coordinate system to another ) 
我在一个坐标系中有一组点,我想将它们旋转到Python中的另一个坐标系。基于此答案我写下以下python函数: def change_of_basis(points, initial, final): ''' rotate points/vectors in a 3D coordinate sys...

0  将通用路径设置为Python中的文件(没有循环)  ( Setting universal path to file in python without for loop ) 
我正在尝试设置我的工作目录,以便它将在所有机器上是通用的 - 但没有循环。我正在使用以下代码,基于此线程:在目录中查找特定路径在Python import os try: ...

0  pyabodb - 如何使用扫描(attributes_to_get = [...])  ( Pynamodb how to use scanattributes to get ) 
我正在使用 pynamodb==3.3.3 要使用 attributes_to_get 条件扫描项目,但是我无法解决: File "/Users/user/Documents/project/script.py", line 250, in filter_writable_snapshots exis...

2  我不明白Python日志记录模块如何读取其执行代码  ( I dont understand how python logging module reads its execution code ) 
下面是我的代码 MarketDataProvider3 当我运行程序时,它会创建文件'logging2测试',但它没有记录日志,虽然我已经告诉程序在第19行录制日志,但是>真的可以使用一些解释。谢谢 ...

7  修改冷却台装饰器以用于方法而不是功能  ( Modifying a cooldown decorator to work for methods instead of functions ) 
我正在尝试创建一个装饰器,它可以用于对它们应用"Cooldown" 的方法,这意味着它们不能在特定持续时间内多次调用。我已经为函数创建了一个: >>> @cooldown(5) ... def f(): ... print('f() was called') ... >>> f() f() was cal...

0  服务兼容性意外退出。状态代码是:-9  ( Service chromedriver unexpectedly exited status code was 9 ) 
我对 9988876612 进行了诸多问题,用于使用solemiumings。 $http.get()3 已安装并将其放在与Python文件相同的文件夹中。似乎加载jupyter小区几秒钟的所有建议都被拒绝了以下消息: $http.get()4 其中我使用 $http.get()5 下载它们。在这里我的代码: ...

3  如何使用名称创建多个文件夹,并将多个zips提取到每个不同的文件夹,使用python?  ( How to create multiple folders with names and extract multiple zips to each dif ) 
我无法创建许多不同的目录,了解包含不同栅格数据的许多不同的ZIP文件夹,然后将所有zips从清洁脚本中的新文件夹中提取到新文件夹。 我已经完成了我的代码的任务是非常长而凌乱的。我需要具有标有 99887663 , 99887664 等的文件夹,然后在这些目录中,我需要子文件夹,例如 99887665 ,<代码> N...

1  从文本文件创建用户名  ( Creating username from text file ) 
我只知道我是一个对这个的numpty,所以忍受了我。到目前为止已经尝试过我最好的! 与文本文件中的读取行与姓氏和姓氏(有些具有中间名)以生成in inneded版本的foreName和任何中间名称的用户名。如果有重复的话,我们从他们的姓氏中拉到第一个字母。如果仍然重复,我们后缀1,然后从那里开始计算更多重复 - 我只...

2  rq工作人员扔“valueerror”  ( Rq worker throwing valueerror ) 
我试图在我的烧瓶申请上获取RQ / RQ工作者。我试图将其缩至一个非常简单的测试用例。这是一般的想法: 用户访问 /test 页面。触发要排队的作业并返回排队作业的 job_key 工人( worker.py )处理排队的作业。 用户可以访问 /retrieve/<job_key> 页面来检索结果。 [这未显示...

1  在Python中转换秒和时间  ( Convert seconds to date and time in python ) 
我有一个包含秒的列的数据帧,我想将列转换为日期和时间,并使用包含日期和时间的列保存文件.I在几秒钟内有一个列的列 time 2384798300 1500353475 7006557825 1239779541 1237529231 我能够这样做,但仅通过插入我想要使用以下代码转换的秒数: da...

2  将主列表与CSV行中的单个列表进行比较  ( Comparing master list to individual lists in a csv row ) 
我正在尝试自动化我的教室,我正在击中墙壁,将我的总学生列表与课程和学生的DataFrame进行比较。最终,代码将返回全类类列表。 首先,我的学生总计列表称为 all_kids 。 all_kids=['Kevin', 'Jack', 'Caroline', 'Grace', 'Harry', 'Sam'] df_...

0  Python数据类型类型代码综合表或资源  ( Python data type type codes comprehensive table or resource ) 
今天,在其他几个场合,我收到了这样的错误: {TypeError}ufunc subtract cannot use operands with types dtype('<M8[us]') and dtype('O'). 在其他日子里,我想做一些printf类型命令,并处于丢失的损失,该字符用于某些钝数据类...




© 2021 it.wenda123.org All Rights Reserved. 问答之家 版权所有