Issue851449
This issue tracker has been migrated to GitHub,
and is currently read-only.
For more information,
see the GitHub FAQs in the Python's Developer Guide.
Created on 2003-11-30 05:40 by edloper, last changed 2022-04-11 14:56 by admin. This issue is now closed.
Messages (4) | |||
---|---|---|---|
msg19206 - (view) | Author: Edward Loper (edloper) * | Date: 2003-11-30 05:40 | |
According to the current reference docs, "If [a class] defines __cmp__() or __eq__() but not __hash__(), its instances will not be usable as dictionary keys. [1] But this doesn't work quite like you'd think for new-style classes: Python 2.3 (#1, Sep 13 2003, 00:49:11) [GCC 3.3 20030304 (Apple Computer, Inc. build 1495)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> class A(object): ... def __cmp__(self, other): return -1 >>> print {A():1} {<__main__.A object at 0x71cf0>: 1} The problem is that object defines a default __hash__ method: >>> print A.__hash__ <slot wrapper '__hash__' of 'object' objects> So the dictionary class thinks that the object is hashable. But given that we've overridden cmp, there's no reason to believe that __hash__ is still valid. The only workaround I've found is to manually add a __hash__ method that raises the appropriate exception: >>> class A(object): ... def __cmp__(self, other): return -1 ... def __hash__(self): ... raise TypeError, ('%s objects are unhashable' % ... self.__class__) But it seems like this should be fixed in Python itself. I can think of 2 reasonable ways to fix it: - change object.__hash__() to raise a TypeError if __cmp__ or __eq__ is overridden. - change hash() to raise a TypeError if given an object that overrides __cmp__ or __eq__ but not __hash__. So.. Is this a real bug, or am I missing something? And if so, what's the prefered place to fix it? (I'd be happy to try to put together a patch for it, if it is indeed broken.) -Edward [1] http://www.python.org/doc/current/ref/ customization.html |
|||
msg19207 - (view) | Author: Raymond Hettinger (rhettinger) * | Date: 2003-12-01 10:52 | |
Logged In: YES user_id=80475 It has been a subject of debate but the behavior is already cast in stone. Anything inheriting from object is hashable by default. The preferred way to make things unhashable is: def __hash__(self) return NotImplemented |
|||
msg19208 - (view) | Author: Edward Loper (edloper) * | Date: 2003-12-01 14:49 | |
Logged In: YES user_id=195958 Can you point me to the debate? I searched the python & python-dev mailing lists, and only came up with statements that suggested that people think that it does have the documented behavior. E.g., "A new-style class would NOT become unhashable by implementing __eq__ w/o __hash__, although its INSTANCES would." <http://groups.yahoo.com/group/python- list/message/108397> Using "return NotImplemented" does *not* seem like the right thing to do: if I try to use such an object as a dictionary key, it gives the confusing error "TypeError: an integer is required," since dict expects hash() to return an int. If this behavior is indeed set in stone, then this should be changed to a documentation bug, and the originally referenced page <://www.python.org/doc/current/ref/customization.html> should be updated to describe the actual behavior for new- style classes. -Edward |
|||
msg19209 - (view) | Author: Raymond Hettinger (rhettinger) * | Date: 2003-12-02 07:17 | |
Logged In: YES user_id=80475 I should have been clearer. The bug has been discussed several times before (SF 475877, 660098, and 730087) and while unresolved leaves us in a workable position of explicitly defining a nohash function. I rechecked my notes, the right way to implement such a function is to raise a TypeError. I misrememberes returning NotImplemented which is the technique for overcoming certain issues related to __cmp__. |
History | |||
---|---|---|---|
Date | User | Action | Args |
2022-04-11 14:56:01 | admin | set | github: 39631 |
2003-11-30 05:40:01 | edloper | create |