Создание именованного элемента с пользовательской хэш-функцией

Скажем, у меня есть 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

Итак, что я могу сделать? Или это плохая идея, и я должен просто написать свой собственный класс с нуля?

Ответы

Ответ 1

Я думаю, что что-то не так с вашим кодом (я предполагаю, что вы создали экземпляр кортежа с тем же именем, поэтому 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

Ответ 2

Начиная с 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)