Bjö*_*lex 46 python inheritance tuples
假设我有namedtuple
这样的:
EdgeBase = namedtuple("EdgeBase", "left, right")
Run Code Online (Sandbox Code Playgroud)
我想为此实现一个自定义哈希函数,所以我创建了以下子类:
class Edge(EdgeBase):
def __hash__(self):
return hash(self.left) * hash(self.right)
Run Code Online (Sandbox Code Playgroud)
由于对象是不可变的,我希望哈希值只计算一次,所以我这样做:
class Edge(EdgeBase):
def __init__(self, left, right):
self._hash = hash(self.left) * hash(self.right)
def __hash__(self):
return self._hash
Run Code Online (Sandbox Code Playgroud)
这似乎有效,但我真的不确定Python中的子类化和初始化,尤其是使用元组.这个解决方案有什么缺陷吗?有推荐的方法怎么做?好吗?提前致谢.
hab*_*bit 51
编辑2017年: 结果namedtuple
不是一个好主意.attrs是现代的替代品.
class Edge(EdgeBase):
def __new__(cls, left, right):
self = super(Edge, cls).__new__(cls, left, right)
self._hash = hash(self.left) * hash(self.right)
return self
def __hash__(self):
return self._hash
Run Code Online (Sandbox Code Playgroud)
__new__
你想在这里调用,因为元组是不可变的.创建不可变对象__new__
然后返回给用户,而不是填入数据__init__
.
cls
必须通过两次到super
调用,__new__
因为__new__
,由于历史/奇怪的原因隐含a staticmethod
.
在 Python 3.7+ 中,您现在可以使用数据类轻松构建可哈希类。
代码
假设和int
的类型,我们使用默认的 hash via +关键字:left
right
unsafe_hash
import dataclasses as dc
@dc.dataclass(unsafe_hash=True)
class Edge:
left: int
right: int
hash(Edge(1, 2))
# 3713081631934410656
Run Code Online (Sandbox Code Playgroud)
现在我们可以使用这些(可变的)可哈希对象作为集合中的元素或(字典中的键)。
{Edge(1, 2), Edge(1, 2), Edge(2, 1), Edge(2, 3)}
# {Edge(left=1, right=2), Edge(left=2, right=1), Edge(left=2, right=3)}
Run Code Online (Sandbox Code Playgroud)
细节
我们也可以重写该__hash__
函数:
@dc.dataclass
class Edge:
left: int
right: int
def __post_init__(self):
# Add custom hashing function here
self._hash = hash((self.left, self.right)) # emulates default
def __hash__(self):
return self._hash
hash(Edge(1, 2))
# 3713081631934410656
Run Code Online (Sandbox Code Playgroud)
扩展@ShadowRanger的评论,OP的自定义哈希函数不可靠。特别地,属性值可以互换,例如hash(Edge(1, 2)) == hash(Edge(2, 1))
,这可能是无意的。
+注意,名称“不安全”表明尽管是可变对象,仍将使用默认哈希。这可能是不受欢迎的,特别是在需要不可变键的字典中。可以使用适当的关键字打开不可变哈希。另请参阅有关数据类中的散列逻辑和相关问题的更多信息。
归档时间: |
|
查看次数: |
17426 次 |
最近记录: |