getting rid of default object.__hash__ (SF 660098)
New-style classes inherit a default __hash__ from object, but this is incorrect if the inheriting object defines __eq__ or __cmp__. This has been reported several times; the roll-up SF entry is 660098, which has the proposed patch attached as newpatch.txt. I've long pondered this, and it seems the best solution is to simply not define __hash__ on the base object class. After all, you don't inherit __eq__ or __cmp__ either; the default comparison behavior is supplied by intrinsic behavior of comparisons, and the default hash() behavior is also supplied by intrinsic behavior of hash(). Does anybody have any reason why I shouldn't check in this change in 2.4? There's no unit test that fails if I do this. It *is* a slight incompatibility though: if someone implemented their __hash__ in terms of object.__hash__, they would get a somewhat puzzling error message after the change, because object.__hash__ will refer to the type.__hash__ function bound to object, and refuse to take an argument:
object.__hash__() 135328576 object.__hash__(42) Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: expected 0 arguments, got 1
Since the default hash simply takes id() of the object, it's easy to fix such code once the failure is understood though. --Guido van Rossum (home page: http://www.python.org/~guido/)
On Mon, 2003-12-22 at 16:04, Guido van Rossum wrote:
object.__hash__() 135328576 object.__hash__(42) Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: expected 0 arguments, got 1
Would it be better if object.__hash__() raised a NotImplementedError? -Barry
object.__hash__() 135328576 object.__hash__(42) Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: expected 0 arguments, got 1
Would it be better if object.__hash__() raised a NotImplementedError?
It can't -- it's type.__hash__(object). --Guido van Rossum (home page: http://www.python.org/~guido/)
[Barry]
Would it be better if object.__hash__() raised a NotImplementedError?
[Guido]
It can't -- it's type.__hash__(object).
If I understand Barry's suggestion correctly, he means to keep object.__hash__, but have it raise a specific, meaningful error instead of making a potentially incorrect assumption as it does now. E.g. (not real code, since this would behave differently in Py 2.3.3)
class Works(object): pass class Breaks(object): ... def __cmp__(): return 0 # All instances are created equal! work = Works() break = Breaks() hash(work) 45632543 hash(break) Traceback (most recent call last): <Traceback info> NotImplementedError: Must explicitly define __hash__ for non-default comparisons
hash(work) is fine, since there is no __cmp__ or __eq__ override in Works, and hence object.__hash__ never gets called. hash(break) raises the exception because of the existence of the (rather useless) __cmp__ function in the Breaks class. Cheers, Nick. -- Nick Coghlan | Brisbane, Australia Email: ncoghlan@email.com | Mobile: +61 409 573 268
On Tue, 2003-12-23 at 05:03, Nick Coghlan wrote:
If I understand Barry's suggestion correctly, he means to keep object.__hash__, but have it raise a specific, meaningful error instead of making a potentially incorrect assumption as it does now.
Right! Thanks Nick. -Barry
participants (3)
-
Barry Warsaw
-
Guido van Rossum
-
Nick Coghlan