[Tutor] unhashable objects (unrelated to previous topic)

Orri Ganel singingxduck at gmail.com
Mon Mar 28 01:08:41 CEST 2005


Hello all,

I am attempting to implement a LinkedList in Python, and in doing so,
have created a Node class which represents the elements of the
LinkedList.  However, since these Nodes have custom-defined __lt__(),
__gt__(), __le__(), __ge__(), __eq__(), and __ne__() methods, they
are, for some reason, unhashable.  When I comment out these methods,
Python makes no complaint. But when they are present, 'TypeError:
unhashable instance' is raised when attempting to use a Node as a key
in a dictionary.  The full error appears:

Traceback (most recent call last):
  File "<pyshell#4>", line 1, in -toplevel-
    a.append(0)
  File "C:\Documents and Settings\Owner\Desktop\LinkedList.py", line
217, in append
    self.lltopl[self.head] = self.pylist[0]
TypeError: unhashable instance

; the relevant code being:

class LinkedList:
       def __init__(self,node=None):
               """x.__init__(...) initializes x; see
x.__class__.__doc__ for signature"""
               self.length = 0
               self.pylist = []
               self.lltopl = {}
               if node is not None and type(node) == list:
                       self.head = None
                       self.tail = None
                       for i in range(len(node)):
                               self.append(node[i])
               elif node is not None and isinstance(node, LinkedList):
                               self.head = None
                               self.tail = None
                               self.appendlist(node)
               else:
                       if node is not None and not isinstance(node, Node):
                               self.length += 1
                               self.pylist.append(Node(node).cargo)
                               self.head = Node(node)
                       elif node:
                               self.length += 1
                               self.pylist.append(node.cargo)
                               self.head = node
                       else:   self.head = node
                       self.tail = None
                       if len(self.pylist) != 0:
                               self.lltopl[self.head] = self.pylist[0]
                       if self.head:
                               nod = self.head
                               while nod.next:
                                       self.append(nod.next)
                                       nod = nod.next
                               self.head.prev = None
       def append(self, cargo):
               """Only for the appending of single Nodes.
               To append multiple Nodes linked with .next
               and .prev, just use appendlist(linkedlist)
               method"""
               if not isinstance(cargo, Node):
                       node = Node(cargo)
               else: node = cargo
               node.next = None
               node.prev = None
               if not self.head:
                       self.head = node
                       self.pylist.append(self.head.cargo)
                       self.lltopl[self.head] = self.pylist[0]
               elif self.tail:
                       self.tail.next = node
                       node.prev = self.tail
                       self.tail = node
                       self.pylist.append(self.tail.cargo)
                       self.lltopl[self.tail] = self.pylist[-1]
               else:
                       self.head.next = node
                       node.prev = self.head
                       self.tail = node
                       self.pylist.append(self.tail.cargo)
                       self.lltopl[self.tail] = self.pylist[-1]
               self.length += 1
               self.head.prev = None
               return True

class Node:
##       def __eq__(self, y):
##               """x.__eq__(y) <==> x==y"""
##               try:
##                       return self.cargo == y.cargo
##               except:
##                       return self.cargo == y
##       def __ge__(self, y):
##               """x.__ge__(y) <==> x>=y"""
##               try:
##                       return self.cargo >= y.cargo
##               except:
##                       return self.cargo >= y
##       def __gt__(self, y):
##               """x.__gt__(y) <==> x>y"""
##               try:
##                       return self.cargo > y.cargo
##               except:
##                       return self.cargo > y
       def __init__(self, cargo=None, prev=None, next=None):
               self.cargo = cargo
               self.prev = prev
               self.next = next
##       def __le__(self, y):
##               """x.__le__(y) <==> x<=y"""
##               try:
##                       return self.cargo <= y.cargo
##               except:
##                       return self.cargo <= y
##       def __lt__(self, y):
##               """x.__lt__(y) <==> x<y"""
##               try:
##                       return self.cargo < y.cargo
##               except:
##                       return self.cargo < y
##       def __ne__(self, y):
##               """x.__ne__(y) <==> x!=y"""
##               try:
##                       return self.cargo != y.cargo
##               except:
##                       return self.cargo != y
       def __str__(self):
               return str(self.cargo)
       def cequals(self, node):
               if not isinstance(node, Node):
                       node = Node(node)
               if self.cargo == node.cargo:
                       return True
               return False
       def equals(self, node):
               if self.cequals(node) and self.nequals(node) and
self.pequals(node):
                       return True
               return False
       def pequals(self, node):
               if not isinstance(node, Node):
                       if self.prev == node:
                               return True
               elif self.prev == node.prev:
                       return True
               return False
       def nequals(self, node):
               if not isinstance(node, Node):
                       if self.next == node:
                               return True
               elif self.next == node.next:
                       return True
               return False

Since the code here is unfinished and not in full form in any case,
its not yet ready for suggestions, however, once I'm done with the
implementation (a matter of finishing the docstrings and making
unittests), I will welcome suggestions and comments.  However, if
anyone has any idea why custom comparing methods make an object
unhashable, I'd be grateful.

Thanks in advance,
Orri
-- 
Email: singingxduck AT gmail DOT com
AIM: singingxduck
Programming Python for the fun of it.


More information about the Tutor mailing list