说a我在python3中有一个数据类。我希望能够散列和排序这些对象。
我只想在id上订购/散列它们。
我在文档中看到,我可以只实现_hash_和所有这些,但我想让数据类为我做这些工作,因为它们旨在处理这些。
from dataclasses import dataclass, field
@dataclass(eq=True, order=True)
class Category:
id: str = field(compare=True)
name: str = field(default="set this in post_init", compare=False)
a = sorted(list(set([ Category(id='x'), Category(id='y')])))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'Category'
TL;博士
将< code>frozen=True与< code>eq=True结合使用(这将使实例不可变)。
长回答
从文档中:
__hash__()
由内置 hash()
使用,并且当对象添加到哈希集合(如字典和集)时使用。具有__hash__()
意味着该类的实例是不可变的。可变性是一个复杂的属性,取决于程序员的意图、__eq__()
的存在和行为,以及 dataclass()
装饰器中 eq 和冻结标志的值。
默认情况下,dataclass()
不会隐式添加__hash__()
方法,除非这样做是安全的。它也不会添加或更改现有的显式定义的__hash__()
方法。设置类属性__hash__=无
对Python有特定的含义,如__hash代码>留档中所述。
如果
__hash__()
未显式定义,或设置为None,则dataclass()
可能会添加隐式
方法。尽管不推荐,但您可以强制
dataclass()
创建一个
__hash_()
方法,其中
。如果您的类在逻辑上是不可变的,但仍然可以修改,则可能会出现这种情况。这是一个特殊的用例,应该仔细考虑。
以下是管理< code>__hash__()
方法的隐式创建的规则。请注意,您不能在dataclass中既有显式的< code>__hash__()方法,又设置< code > unsafe _ hash = True ;这将导致一个< code>TypeError。
如果eq和freezed都为true,默认情况下dataclass()
将为您生成一个__hash_()
方法。如果eq为true,freezed为false,__hash__()
将设置为None,将其标记为不可损坏(因为它是可变的)。如果eq为false,__hash__()
将保持不变,这意味着将使用超类的__hash()
方法(如果超类是object,则意味着它将回退到基于id的哈希)。
我想加一个unsafe_hash使用的特别说明。
通过设置compare=False或hash=False,可以将字段排除在哈希比较之外。(默认情况下,哈希继承自compare)。
如果您将节点存储在图中,但希望在不破坏其散列的情况下标记已访问的节点(例如,如果它们位于一组未访问的节点中…),这可能会很有用。
from dataclasses import dataclass, field
@dataclass(unsafe_hash=True)
class node:
x:int
visit_count: int = field(default=10, compare=False) # hash inherits compare setting. So valid.
# visit_count: int = field(default=False, hash=False) # also valid. Arguably easier to read, but can break some compare code.
# visit_count: int = False # if mutated, hashing breaks. (3* printed)
s = set()
n = node(1)
s.add(n)
if n in s: print("1* n in s")
n.visit_count = 11
if n in s:
print("2* n still in s")
else:
print("3* n is lost to the void because hashing broke.")
这花了我几个小时才弄清楚...我发现的有用的进一步阅读材料是关于数据类的python文档。具体请参阅字段文档和数据类 arg 文档。https://docs.python.org/3/library/dataclasses.html
从文档中:
以下是管理隐式创建__hash__()
方法的规则:
[...]
如果 eq
和冻结
都为真,则默认情况下,dataclass()
将为您生成一个 __hash__()
方法。如果 eq
为 true 且冻结
为假,则 __hash__()
将设置为 None
,将其标记为不可哈希(确实如此,因为它是可变的)。如果 eq
为 false,则__hash__()
将保持不变,这意味着将使用超类的 __hash__()
方法(如果超类是对象,这意味着它将回退到基于 id 的哈希)。
由于您设置了 eq=True
并保持冻结
状态,因此您的数据类是不可哈希的。
您有3个选择:
>
冻结=True
(除了eq=True
),这将使您的类不可变且可散列。Setunsafe_hash=True
,这将创建一个__hash__
方法,但使您的类保持可变,因此如果您的类的实例在存储在dicor set中时被修改,则可能会出现问题:
cat = Category('foo', 'bar')
categories = {cat}
cat.id = 'baz'
print(cat in categories) # False
问题内容: 在python中使用户定义的类可排序和/或可哈希化时,需要重写/实现哪些方法? 需要注意的陷阱是什么? 我输入解释器以获取内置字典的方法列表。其中,我假设我需要一些实现 与Python2相比,必须为Python3实现哪些方法有区别吗? 问题答案: 我差点把它作为对其他答案的评论,但这本身就是一个答案。 为了使您的项目可排序,它们只需要实现。这是内置排序使用的唯一方法。 其他比较还是仅在
问题内容: Java的访问级别表显示了用于控制对类成员的访问的4个不同选项: 但是,没有用于“仅类和子类可访问”的修饰符。那是: 是否有可能在Java中定义这种访问级别? 如果是这样,怎么办? 如果无法做到这一点,那一定是由于经过深思熟虑的设计原则。如果是这样,那是什么原则。换句话说,为什么在Java中具有这样的访问级别不是一个好主意? 问题答案: 设计原则是开发人员不要恶意入侵自己的程序。如果您
问题内容: 如何使类可序列化? 一个简单的类: 我应该怎么做才能获得以下输出: 问题答案: 你对预期的输出有想法吗?例如这样做吗? 在这种情况下,你只能致电。 如果你想要更多的自定义输出,则必须继承并实现自己的自定义序列化。 有关一个简单的示例,请参见下文。 然后,将该类作为 传递给方法: 如果你也想解码,那么你将有一个自定义供应类。例如
问题内容: 这是我的代码: 为什么会这样呢? 第一个和第三个对象具有相同的内容和相同的哈希值,但它们讲述了3个唯一的对象? 问题答案: 您还需要以兼容的方式进行定义–否则,相等性将基于对象身份。 在Python 2上,建议您还定义与保持一致。在Python 3上,默认实现将为您委托。
问题内容: 如何使Python类可序列化? 一个简单的类: 我应该怎么做才能获得以下输出: 没有错误 问题答案: 你对预期的输出有想法吗?例如这样做吗? 在这种情况下,你只能致电。 如果你想要更多的自定义输出,则必须继承并实现自己的自定义序列化。 有关一个简单的示例,请参见下文。 然后,将该类作为传递给方法: 如果你也想解码,那么你将有一个自定义供应给类。例如
想给方法自定义数据类型,通过资料查到可以用 dataclass 这样就很简洁,但貌似传入必须是实例化的方式,我更希望是字典的形式,请问有什么简洁的好的方法?