Creating a namedtuple with a custom hash function
I think there is something wrong with your code (my guess is that you created an instance of the tuple with the same name, so fooTuple
is now a tuple, not a tuple class), because subclassing the named tuple like that should work. Anyway, you don't need to redefine the constructor. You can just add the hash function:
In [1]: from collections import namedtupleIn [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
Starting in Python 3.6.1, this can be achieved more cleanly with the typing.NamedTuple
class (as long as you are OK with type hints):
from typing import NamedTuple, Anyclass FooTuple(NamedTuple): item1: Any item2: Any def __hash__(self): return hash(self.item1) * hash(self.item2)
A namedtuple
with a custom __hash__
function is useful to store immutable data models into dict
and set
For example:
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)])
Override both __eq__
and __hash__
allows grouping businesses into a set
, ensuring that each business line is unique in the collection:
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) == 3assert len(businesses_by_line) == 2