Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I add <some list>.append to a python set?

Tags:

python

set

Why is it that I can add normal callables and methods to a set, but not <some list>.append (for instance)?

For Example:

>>> l = []
>>> s = set()
>>> s.add(l.append)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> type(l.append)
<type 'builtin_function_or_method'>
>>> type(map)
<type 'builtin_function_or_method'>
>>> s.add(map)
>>> def func(): print 'func'
... 
>>> s.add(func)
>>> print s
set([<built-in function map>, <function func at 0x10a659758>])

Edit: I noticed that l.append.__hash__() also gives this error

like image 506
Peter Gibson Avatar asked Nov 28 '12 01:11

Peter Gibson


3 Answers

You cannot add lists to a set because lists are mutable. Only immutable objects can be added to sets.

l.append is an instance method. You can think of it as if it were the tuple (l, list.append) — that is, it's the list.append() method tied to the particular list l. The list.append() method is immutable but l is not. So while you can add list.append to the set you can't add l.append.

This works:

>>> s.add(list.append)

This does not work:

>>> s.add((l, list.append))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
like image 83
John Kugelman Avatar answered Sep 28 '22 06:09

John Kugelman


You're not trying to add list.append. You're trying to add l.append which is an instance method, not a class method. list instances aren't hashable, and apparently their methods aren't hashable either.

Think of it this way. You have 2 lists:

lfoo = []
lbar = []

Now you want to add their respective appends to your set:

s = set()
s.add(lfoo.append)
s.add(lbar.append)

Now when you do the hash lookup for the set, you can't just rely on the function portion of the instance method. Indeed, lfoo and lbar ultimately use the same function (list.append). So that isn't a unique hash. The way you make it unique is by attaching it to an instance. However, the instance doesn't support hashing, so the set has no way of telling the difference between lfoo.append and lbar.append.

like image 22
mgilson Avatar answered Sep 28 '22 07:09

mgilson


In Python, list objects aren't hashable. I suspect that when you hash an instance method, it incorporates the hash of the instance its bound to. As such, you get the TypeError.

like image 43
bradley.ayers Avatar answered Sep 28 '22 08:09

bradley.ayers