12

I understand why a tuple which contains a mutable object like list is not hashable, since list items in the tuple can still be updated.

example:

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

While this is not hashable:

# Not hashable

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

The above make sense to me.

But when I create a namedtuple with list items it is still hashable:

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

and when I add a list:

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

Why this difference between tuples and namedtuples?

4
  • See stackoverflow.com/questions/11324271/… Commented Oct 22, 2018 at 0:07
  • 1
    "But when I create a namedtuple with list as items it is still hashable," Where do you do that? You create a named-tuple with a string, 'adam' and an int, 20...? Commented Oct 22, 2018 at 0:40
  • 3
    Creating a namedtuple class via a list is not at all the same as creating an instance that contains a list. Commented Oct 22, 2018 at 0:46
  • 2
    Write hash(x), not x.__hash__(). Commented Oct 22, 2018 at 0:47

1 Answer 1

8

But when I create a namedtuple with list as items it is still hashable...

You never do that. You create a named-tuple with a str, 'adam' and an int, 20

The following:

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

And

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

Do not create namedtuple objects, they create namedtuple classes. According to the docs:

Returns a new tuple subclass named typename.

In other words, collections.namedtuple is a factory function that returns a class. If you create instances of those classes, their instances follow the same rules as regular tuple instances.

So consider:

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

TestTuple, the return value of the namedtuple factory function, is not a namedtuple instance, it is an instance of type, like all other classes.

When you create instances of this class:

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

They follow the usual rules of hashability that regular tuple objects do:

>>> 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'

Note, the fieldnames argument accepts either a sequence (e.g. a list) of fieldnames, or for convenience, a space/comma-delimited string of fieldnames, so also from the docs:

... The field_names are a sequence of strings such as ['x', 'y']. Alternatively, field_names can be a single string with each fieldname separated by whitespace and/or commas, for example 'x y' or 'x, y'.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.