0

I am trying to implement the hash definition suggested here but I am getting an error when trying to use hash on the class. The class is defined as so:

class Metabolite:
    def __init__(self, name_in='', id_in='', synonyms_in=[], InChIKey_in='', formulae_in=[], charge_in='', ecs_in=[], mtk_in = [],  mtb_in = '', mtm_in = '', mts_in = '', bkm_id_in = '', source_in = ''):
        self.name = name_in
        self.id = id_in
        self.formulae = formulae_in
        self.inchikey = InChIKey_in
        self.synonyms = synonyms_in
        self.charge = charge_in
        self.ecs = ecs_in
        self.mtb = mtb_in
        self.mtk = mtk_in
        self.mtm = mtm_in
        self.mts = mts_in
        self.bkm_id = bkm_id_in
        self.source = source_in

    def key(self):
        return self.id, self.inchikey, self.mts, self.mtk, self.mtb, self.mtk

    def __key(self):
        return tuple([self.id, self.inchikey, self.mts, self.mtk, self.mtb, self.mtk])

    def __eq__(self, other):
        return self.__key() == other.__key()

    def __hash__(self):
        return hash(tuple(self.__key()))

However on creating an instance of this class and asking for a hash I get the following:

>>> met = Metabolite('this_metabolite', '10002', 'AADBRHFDG')
>>> hash(met)

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-8-7941e6f25128> in <module>()
----> 1 hash(met)

classes.py in __hash__(self)
     27 
     28     def __hash__(self):
---> 29         return hash(tuple(self.__key()))
     30 
     31 

TypeError: unhashable type: 'list'

despite my desperate attempts in the class definition to force the type to be a (hashable) tuple. I am new to classes in Python, any help would be greatly appreciated.

When run in IDLE, the error comes up as:

Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    hash(met)
  File "<string>", line 27, in __hash__
TypeError: unhashable type: 'list'

SOLVED: thanks to those who responded.

A tuple containing an empty list will not work:

>>> my_tuple = tuple(('a',[]))

>>> type(my_tuple)

tuple

>>> hash(my_tuple)

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-28-f63af41cc75b> in <module>()
----> 1 hash(my_tuple)

TypeError: unhashable type: 'list'

so I had to create a list of my variables before returning them in __key():

def __key(self):
    key_list = []
    key_list.append(self.id)
    key_list.append(self.inchikey)
    key_list.append(self.mts)
    key_list.append(self.mtb)
    for entry in self.mtk:
        key_list.append(entry)
    return tuple(key_list)
6
  • I just ran your class in idle, and I don't get this error. Instead, I get 301521507 as a result. Commented Jan 29, 2013 at 13:14
  • I didn't get an error either, what version of python are you running? Commented Jan 29, 2013 at 13:24
  • 1
    Same here, no errors, check your code without IPython, it is known for its side-effects. Commented Jan 29, 2013 at 13:25
  • OK thanks a lot, this was just a toy example of what I had originally run and now I can't get it to reproduce the error ... have edited the post with my actual code which throws up the error. AND I'll check it in another interpreter Commented Jan 29, 2013 at 13:29
  • 1
    @WillBryant: If your question is solved, it's a good idea to answer your own question and accept it (That gets it off the list of unanswered questions :-) Commented Jan 29, 2013 at 14:13

1 Answer 1

1

The problem is that the mtk attribute is a list (by default). Mutable sequence types cannot be hashed and since your key contains mtk (twice), the key is not hashable (even if the key itself is a tuple).

If you modify your key generation as follows, then it becomes hashable (but it might prove seriously inefficient):

def __key(self):
    mtk = tuple(self.mtk)
    return tuple([self.id, self.inchikey, self.mts, mtk, self.mtb, mtk])

This returns in Python 2.7 (code pasted from your question with above modification):

>>> met = Metabolite('this_metabolite', '10002', 'AADBRHFDG')
>>> hash(met)
7276685348836095537
Sign up to request clarification or add additional context in comments.

2 Comments

posted as it is a simpler solution than the one you indicate. Well, IMHO at least :)
Thanks for the answer, yes that's certainly more elegant than my code!

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.