【问题标题】:Making a list subclass hashable [closed]使列表子类可散列[关闭]
【发布时间】:2012-05-02 11:38:21
【问题描述】:

我想从list 派生一个类,向它添加一些实例属性,并使其可散列。有什么好的(快速而整洁的)方法?

更新:

我删除了一个用例的冗长解释。我还将一个相关但单独的问题移至different question

【问题讨论】:

  • 很难准确地说出你在问什么。
  • 为什么不能使用元组?如果只是关于具有命名属性,则有namedtuple
  • 你能用hash(tuple(self))吗?
  • @JoelCornett:如何为从列表派生的类编写哈希函数,其中还包含其他属性。
  • @delnan:在我使用__init__ 方法之前,我不知道tuple 的值。到那时告诉基地tuple 我希望它包含什么已经太晚了。

标签: python list python-3.x immutability hashable


【解决方案1】:

这段代码很好。您正在制作列表的副本,这可能会有点慢。

def __hash__(self):
    return hash(tuple(self.list_attribute))

如果您想更快,您有多种选择。

  • list_attribute 存储为元组,而不是列表(完全构造后)
  • init 时间计算一次哈希并存储哈希值。您可以这样做,因为您的类是不可变的,因此哈希值永远不会改变。
  • 编写您自己的哈希函数。这是hash function for tuple,做类似的事情。

【讨论】:

  • 鉴于我现在将问题缩短为仅关注子类案例,元组的选项消失了(因为它不能在 __init__ 中更改)。在__init__ 时间计算是一个好主意 - 但我想知道,这不是一个好主意总是,不只是在这种情况下?不过,它当然会比第三种选择慢。
  • 这完全取决于对象将被散列多少次。如果常见的情况是 0,那么你不想提前做。如果常见情况是很多,那么预计算是最好的。
  • 存储哈希值也会浪费内存,顺便说一句。
【解决方案2】:

您可以将tuple 申请为self

class State(list):
    def __hash__(self):
        return hash((self.some_attribute, tuple(self)))

tuple-ing self 大约需要整个哈希过程的一半时间:

from timeit import timeit

setup = "from __main__ import State; s = State(range(1000)); s.some_attribute = 'foo'"
stmt = "hash(s)"
print(timeit(stmt=stmt, setup=setup, number=100000))

setup = "r = list(range(1000))"
stmt = "tuple(r)"
print(timeit(stmt=stmt, setup=setup, number=100000))

打印

0.9382011891054844
0.3911763069244216

【讨论】:

  • 谢谢。看起来还不错。
【解决方案3】:

这更像是一个评论而不是一个答案,但它太长了,不能成为评论。这是从__new__ 内部访问实例属性的方式:

class Data(tuple):
    def __new__(klass, arg):
        data_inst = tuple.__new__(klass, arg)
        data_inst.min = min(data_inst)
        data_inst.max = max(data_inst)
        return data_inst

>>> d = Data([1,2,3,4])
>>> d
(1, 2, 3, 4)
>>> d.min
1
>>> d.max
4
>>> d1 = Data([1,2,3,4,5,6])
>>> d1.max
6
>>> d.max
4

【讨论】:

  • 但这些将是类属性,而不是实例属性。尝试d1 = Data([1,2,3,4]),然后您会看到d1.min is d.min 的计算结果为True。您不能在实例之间将它们分开。
  • 我觉得不行,试试看
  • 啊,你是对的。我的错,is 仅评估为 True,因为它们是重复使用相同 int 对象的小数字。整洁的!我需要存储临时计算直到之后我打电话给tuple.__new__,但我想这很好。
猜你喜欢
  • 1970-01-01
  • 2015-07-05
  • 2017-07-11
  • 2017-11-23
  • 2021-09-30
  • 1970-01-01
  • 1970-01-01
  • 2019-03-31
  • 1970-01-01
相关资源
最近更新 更多