I am trying to get a list of list of tuples : something like [ [(1,0),(2,0),(3,0)],[(1,1),(2,1),(3,1)....]] I used this statement
set([(a,b)for a in range(3)]for b in range(3)) But it gives me an error
TypeError: unhashable type: 'list' I have 2 questions for the Python Guru's:
a) When I look at the Python definition of Hashable -
"An object is hashable if it has a hash value which never changes during its lifetime (it needs a hash() method)"
when I used dir function on the expression above
dir([(a,b)for a in range(3)]for b in range(3)) it seems to say the __hash__ is there. So, why do I get the error?
I was able to get [[(0, 0), (1, 0), (2, 0)], [(0, 1), (1, 1), (2, 1)], [(0, 2), (1, 2), (2, 2)]] by using the list command :
list(list((a,b) for a in range(3)) for bin range(3)) b)list and set both takes Iterable as parameter. How come one works(list) and another doesn't (set)?
06 Answers
You are creating a set via set(...) call, and set needs hashable items. You can't have set of lists. Because list's arent hashable.
[[(a,b) for a in range(3)] for b in range(3)] is a list. It's not a hashable type. The __hash__ you saw in dir(...) isn't a method, it's just None.
A list comprehension returns a list, you don't need to explicitly use list there, just use:
>>> [[(a,b) for a in range(3)] for b in range(3)] [[(0, 0), (1, 0), (2, 0)], [(0, 1), (1, 1), (2, 1)], [(0, 2), (1, 2), (2, 2)]] Try those:
>>> a = {1, 2, 3} >>> b= [1, 2, 3] >>> type(a) <class 'set'> >>> type(b) <class 'list'> >>> {1, 2, []} Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unhashable type: 'list' >>> print([].__hash__) None >>> [[],[],[]] #list of lists [[], [], []] >>> {[], [], []} #set of lists Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unhashable type: 'list' 1TLDR:
- You can't hash a list, a set, nor a dict to put that into sets
- You can hash a tuple to put it into a set.
Example:
>>> {1, 2, [3, 4]} Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unhashable type: 'list' >>> {1, 2, (3, 4)} set([1, 2, (3, 4)]) Note that hashing is somehow recursive and the above holds true for nested items:
>>> {1, 2, 3, (4, [2, 3])} Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unhashable type: 'list' Dict keys also are hashable, so the above holds for dict keys too.
3A list is unhashable because its contents can change over its lifetime. You can update an item contained in the list at any time.
A list doesn't use a hash for indexing, so it isn't restricted to hashable items.
The real reason because set does not work is the fact, that it uses the hash function to distinguish different values. This means that sets only allows hashable objects. Why a list is not hashable is already pointed out.
... and so you should do something like this:
set(tuple ((a,b) for a in range(3)) for b in range(3)) ... and if needed convert back to list
You'll find that instances of list do not provide a __hash__ --rather, that attribute of each list is actually None (try print [].__hash__). Thus, list is unhashable.
The reason your code works with list and not set is because set constructs a single set of items without duplicates, whereas a list can contain arbitrary data.