unhashable type error

69 views
Skip to first unread message

Harold E.

unread,
Apr 26, 2012, 4:51:15 PM4/26/12
to sy...@googlegroups.com
Hi,

I'm currently implementing the unit systems into sympy (see https://groups.google.com/forum/?fromgroups#!topic/sympy/Vrvwf5CYmWw). The dimensions of an unit are stored in an object which inherits from the dict class. But because of that, when I'm writing something like 2*m, where m is an unit, I got the error "TypeError: unhashable type: dict", appearing in the cache function.
I saw by looking at other topics that in principle it happens because the __hash__ method is not defined, but since here the class inherits from dict, there is no reason that it's not defined. I also tried to make the dimension class deriving from something like Basic, Expr, etc., but I have an error saying that there is a clash between methods. I tried to seehow to fix this, but instead of rewriting from the beginning the dimension class.

krastano...@gmail.com

unread,
Apr 26, 2012, 5:04:02 PM4/26/12
to sy...@googlegroups.com
There is an easy way to check for yourself that the dict build-in does
not have a hash method:

In [1]: d = {1:1}
In [2]: hash(d)
TypeError: unhashable type: 'dict'

Hashes are not defined on mutable objects because the hash of an
object should not change. Thanks to this quality hashes can be used
for cashing.

Cashing and hashes are an important part of the core, this is why for
the moment if you implement something in sympy it should be immutable.

Matthew Rocklin

unread,
Apr 26, 2012, 5:15:46 PM4/26/12
to sy...@googlegroups.com
If you google around you can find a frozendict class that is immutable and hashable. 

Alternatively there is also a SymPy Dict class. 


--
You received this message because you are subscribed to the Google Groups "sympy" group.
To post to this group, send email to sy...@googlegroups.com.
To unsubscribe from this group, send email to sympy+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/sympy?hl=en.


Chris Smith

unread,
Apr 26, 2012, 11:01:00 PM4/26/12
to sy...@googlegroups.com
Here's a frozendict with reference:

```
class frozendict(dict):
# from http://code.activestate.com/recipes/414283-frozen-dictionaries/
def _blocked_attribute(obj):
raise AttributeError("A frozendict cannot be modified.")
_blocked_attribute = property(_blocked_attribute)

__delitem__ = __setitem__ = clear = _blocked_attribute
pop = popitem = setdefault = update = _blocked_attribute

def __new__(cls, *args, **kw):
new = dict.__new__(cls)

args_ = []
for arg in args:
if isinstance(arg, dict):
arg = copy.copy(arg)
for k, v in arg.items():
if isinstance(v, dict):
arg[k] = frozendict(v)
elif isinstance(v, list):
v_ = list()
for elm in v:
if isinstance(elm, dict):
v_.append( frozendict(elm) )
else:
v_.append( elm )
arg[k] = tuple(v_)
args_.append( arg )
else:
args_.append( arg )

dict.__init__(new, *args_, **kw)
return new

def __init__(self, *args, **kw):
pass

def __hash__(self):
try:
return self._cached_hash
except AttributeError:
h = self._cached_hash = hash(frozenset(self.items()))
return h

def __repr__(self):
return "frozendict(%s)" % dict.__repr__(self)
```

Harold E.

unread,
Apr 27, 2012, 6:41:44 AM4/27/12
to sy...@googlegroups.com
In fact, I remembered that dict was not hashable, but by reading the doc I saw "dict.__hash__", so I was thinking that the problem came not from this; actually, this was just a normal point.
So thank for your explanation; finally I did a new class based on tuple but with some dict-behaviors, I think it was the simpler since Dimension is a very simple object.

krastano...@gmail.com

unread,
Apr 27, 2012, 6:46:58 AM4/27/12
to sy...@googlegroups.com
On 27 April 2012 12:41, Harold E. <harold...@gmail.com> wrote:
> In fact, I remembered that dict was not hashable, but by reading the doc I
> saw "dict.__hash__", so I was thinking that the problem came not from this;
> actually, this was just a normal point.
> So thank for your explanation; finally I did a new class based on tuple but
> with some dict-behaviors, I think it was the simpler since Dimension is a
> very simple object.
>
On the other hand the proliferation of simple classes that do the same
thing may be a bad idea. If you have something in the standard library
or in the utilities implemented by sympy it would be best to use it
instead of reimplement it even if it is a five-liner.
Reply all
Reply to author
Forward
0 new messages