0

I understand that a set is not hashable and a tuple is. However,

a = ({1, 2, 3}, {2, 3, 5})
b = ({1, 7}, {3, 0})
{a, b}

returns TypeError: unhashable type: 'set'. Why is that so?

EDIT: Yes, sets are mutable and therefore unhashable. However, tuples, even though being immutable, can have their elements change value AND still remain hashable. Like so:

class I() :
    __init__(self, value) :
        self.value = value
    __incr__(self) :
        self.value += 1
tup = (I(), I())
tup[0].incr()

So why is it not allowed when it's a tuple of sets?

noobw
  • 1
  • 1
  • 2
  • Briefly: because it doesn't make sense for mutable objects to be hashable. – TigerhawkT3 Oct 06 '16 at 00:10
  • There is an answer for that in [here.](http://stackoverflow.com/questions/9755990/why-can-tuples-contain-mutable-items) – Rockybilly Oct 06 '16 at 00:15
  • @TigerhawkT3 his question wasn't actually why set's not hashable, he asked why tuples containing sets is not hashable, which is actually a different question for someone who does not understand how tuples work in Python. Anyway, it is explained in the link I posted. Just wanted to point out it is not an exact duplicate of the question you presented. – Rockybilly Oct 06 '16 at 00:21
  • @Rockybilly, yeah, thanks, that's closer to my question However, why is a tuple of mutable objects is still hashable, when a tuple of sets is not? How is any mutable object different from a set? – noobw Oct 06 '16 at 00:27
  • A tuple of mutable objects is not hashable.(And tuples are not mutable.) Except some cases which is explained in [this](http://stackoverflow.com/questions/4418741/im-able-to-use-a-mutable-object-as-a-dictionary-key-in-python-is-this-not-disa) question – Rockybilly Oct 06 '16 at 00:32
  • You could make a tuple of *frozenset*s if you want something hashable. – kennytm Oct 06 '16 at 09:51

2 Answers2

0

as you have already mentioned correctly, Python has both modifiable and non-changeable datatypes. Also correct is that a set is a mutable datatype, while a tuple is a non-changeable datatype. However, this is only true for the first level of a tuple and not for deeper levels, so it is not true for your objects.

Let us illustrate this principle with an example:

t = ([1,1],[2,2])
id(t) # --> 2588744372096

o we have a tuple t that contains two lists. One could now assume that this tuple could not be changed, because although lists can be changed, tuples cannot. Internally the following happens: The tuple does not directly contain two lists, but in the tuple pointers are stored to the lists. So the element of the tuple at index 0 is a pointer to the list [1,1] and at position 1 is a pointer to the list [2,2]. So we can change the list at will without changing the tuple, because it consists only of pointers that do not change. So let's change the first element of the first list:

t[0][0] = 3
print(t) # --> ([3,1],[2,2])
id(t) # --> 2588744372096

As we can see from the same id of the tuple, it is still the same tuple, the contents of the tuple (the pointers) have not changed either.

You can take a look at the website pythontutor.com, which also shows this aspect graphically. The graphical visualization is also available here: Click me. Further information about pointers can be found here: Information about pointers

Best regards Johannes :)

0

since no one really answered the question, and googlers want quick answer:

my_set = {(1,2), (3,4), (5,6)}

Defines set of tuples

Izik
  • 746
  • 1
  • 9
  • 25