使用自定义哈希函数创建一个namedtuple

Bjö*_*lex 21 python inheritance overriding tuples

说我有namedtuple这样的:

FooTuple = namedtuple("FooTuple", "item1, item2")
Run Code Online (Sandbox Code Playgroud)

我希望以下函数用于散列:

foo_hash(self):
    return hash(self.item1) * (self.item2)
Run Code Online (Sandbox Code Playgroud)

我想要这个,因为我想要item1item2无关的顺序(我将对比较运算符做同样的事情).我想到了两种方法来做到这一点.第一个是:

FooTuple.__hash__ = foo_hash
Run Code Online (Sandbox Code Playgroud)

这有效,但感觉被黑了.所以我尝试了子类化FooTuple:

class EnhancedFooTuple(FooTuple):
    def __init__(self, item1, item2):
        FooTuple.__init__(self, item1, item2)

    # custom hash function here
Run Code Online (Sandbox Code Playgroud)

但后来我明白了:

DeprecationWarning: object.__init__() takes no parameters
Run Code Online (Sandbox Code Playgroud)

那么,我该怎么办?或者这是一个坏主意,我应该从头开始编写我自己的课程?

Luk*_*ský 27

我认为你的代码有问题(我的猜测是你创建了一个具有相同名称的元组实例,所以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
Run Code Online (Sandbox Code Playgroud)

  • 请注意``repr(foo)`仍然会谈论`Foo`.这可以做得更好,因为`class Foo(namedtuple('Foo',['item1','item2'],verbose = False)): (14认同)

ipe*_*rik 13

从 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)
Run Code Online (Sandbox Code Playgroud)