Почему NamedTuple, содержащий изменяемые объекты, может быть хэшируемым, а Tuple, содержащее изменяемые объекты, не допускается? - PullRequest
0 голосов
/ 22 октября 2018

Я понимаю, почему tuple, который содержит изменяемый объект, такой как list, не может быть хэшируемым, поскольку 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__())

Почему такая разница между кортежами и именованными кортежами?

1 Ответ

0 голосов
/ 22 октября 2018

Но когда я создаю именованный кортеж со списком в качестве элементов, он все еще может хэшироваться ...

Вы никогда этого не сделаете.Вы создаете именованный кортеж с str, 'adam' и int, 20

Следующее:

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

И

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

Делать не создавать namedtuple объекты, они создают namedtuple классов .Согласно docs :

Возвращает новый подкласс кортежа с именем typename.

Другими словами, collections.namedtuple - это фабричная функция, которая возвращает класс .Если вы создаете экземпляры этих классов, их экземпляры следуют тем же правилам, что и обычные tuple экземпляры.

Итак, рассмотрим:

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

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 принимает либо последовательность (например, список) имен полей, либо для удобства пробел / запятую-ограниченная строка имен полей, а также из документов:

... Имена полей - это последовательность строк, таких как ['x', 'y'].В качестве альтернативы, field_names могут быть одной строкой, в которой каждое имя поля разделено пробелами и / или запятыми, например, «xy» или «x, y».

...