用自定义哈希函数创建命名元组
假设我有一个叫做 namedtuple
的东西,长这样:
FooTuple = namedtuple("FooTuple", "item1, item2")
我想用下面这个函数来进行哈希处理:
foo_hash(self):
return hash(self.item1) * (self.item2)
我这么做是因为我希望 item1
和 item2
的顺序不重要(我也会对比较操作做同样的处理)。我想到了两种方法来实现这个。第一种方法是:
FooTuple.__hash__ = foo_hash
这个方法可以用,但我觉得有点不太正规。所以我尝试去继承 FooTuple
:
class EnhancedFooTuple(FooTuple):
def __init__(self, item1, item2):
FooTuple.__init__(self, item1, item2)
# custom hash function here
但是我遇到了这个问题:
DeprecationWarning: object.__init__() takes no parameters
那么,我该怎么办呢?或者说这根本就是个坏主意,我应该从头开始写自己的类吗?
3 个回答
0
一个带有自定义 namedtuple
的 __hash__
函数很有用,可以把 不可变的数据模型 存储到 dict
和 set
中。
举个例子:
class Point(namedtuple('Point', ['label', 'lat', 'lng'])):
def __eq__(self, other):
return self.label == other.label
def __hash__(self):
return hash(self.label)
def __str__(self):
return ", ".join([str(self.lat), str(self.lng)])
重写 __eq__
和 __hash__
两个方法,可以把不同的业务分组到一个 set
里,确保每个业务线在这个集合中都是唯一的:
walgreens = Point(label='Drugstore', lat = 37.78735890, lng = -122.40822700)
mcdonalds = Point(label='Restaurant', lat = 37.78735890, lng = -122.40822700)
pizza_hut = Point(label='Restaurant', lat = 37.78735881, lng = -122.40822713)
businesses = [walgreens, mcdonalds, pizza_hut]
businesses_by_line = set(businesses)
assert len(business) == 3
assert len(businesses_by_line) == 2
19
从Python 3.6.1开始,我们可以使用typing.NamedTuple
这个类来更简单地实现这个功能(只要你对类型提示没有意见):
from typing import NamedTuple, Any
class FooTuple(NamedTuple):
item1: Any
item2: Any
def __hash__(self):
return hash(self.item1) * hash(self.item2)
34
我觉得你的代码有点问题(我猜是你创建了一个和元组同名的实例,所以现在fooTuple
变成了一个元组,而不是元组的类),因为像这样继承命名元组应该是可以的。无论如何,你不需要重新定义构造函数。你只需要添加哈希函数就可以了:
In [1]: from collections import namedtuple
In [2]: Foo = namedtuple('Foo', ['item1', 'item2'], verbose=False)
In [3]: class ExtendedFoo(Foo):
...: def __hash__(self):
...: return hash(self.item1) * hash(self.item2)
...:
In [4]: foo = ExtendedFoo(1, 2)
In [5]: hash(foo)
Out[5]: 2