首页 > 解决方案 > 为什么包含可变对象的 NamedTuple 是可散列的,而包含可变对象的 Tuple 不是?

问题描述

我理解为什么tuple包含可变对象的 alist是不可散列的,因为list元组中的项目仍然可以更新。

例子:

# hashable
tuple_test = (1,2,3)
print(tuple_test.__hash__())

虽然这不是可散列的:

# Not hashable

tuple_test2 = (1,2, [1,2])
print(tuple_test2.__hash__())

以上对我来说很有意义。

但是当我创建一个namedtuple带有list项目时它仍然是可散列的:

# hashable
named_tuple = namedtuple("TestTuple", 'name age')

当我添加一个list

# still hashable
named_tuple = namedtuple("TestTuple", ["name", "age"])
print(named_tuple(name="adam", age=20).__hash__())

为什么元组和命名元组之间存在这种差异?

标签: pythonnamedtuple

解决方案


但是当我创建一个以列表为项目的命名元组时,它仍然是可散列的......

你永远不会那样做。您使用 a和 an创建一个命名元组str'adam'int20

以下:

named_tuple = namedtuple("TestTuple", 'name age')

named_tuple = namedtuple("TestTuple", ["name", "age"])

不要创建对象,它们会创建。根据文档namedtuplenamedtuple

返回一个名为 typename 的新元组子类。

换句话说,collections.namedtuple是一个返回的工厂函数。如果您创建这些类的实例,它们的实例遵循与常规实例相同的规则tuple

所以考虑:

>>> from collections import namedtuple
>>> TestTuple = namedtuple('TestTuple', ['name', 'age'])
>>> type(TestTuple)
<class 'type'>
>>> class A: pass
...
>>> type(A)
<class 'type'>

namedtuple工厂函数的返回值 TestTuple不是 namedtuple 实例,它是 的实例type,就像所有其他类一样。

当您创建此类的实例时:

>>> test_tuple = TestTuple('adam',32)
>>> type(test_tuple)
<class '__main__.TestTuple'>

它们遵循常规tuple对象所做的通常的哈希规则:

>>> hash(test_tuple)
5589201399616687819
>>> test_tuple = TestTuple('adam', [32, 31])
>>> hash(test_tuple)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

请注意, fieldnames 参数接受字段名的序列(例如列表),或者为方便起见,接受空格/逗号分隔的字段名字符串,因此也来自文档:

... field_names 是一个字符串序列,例如 ['x', 'y']。或者,field_names 可以是单个字符串,每个字段名由空格和/或逗号分隔,例如“x y”或“x, y”。


推荐阅读