classification
Title: collections.abc.Reversible should not be a subclass of Hashable
Type: behavior Stage: resolved
Components: Library (Lib) Versions: Python 3.9
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: Zac Hatfield-Dodds, gvanrossum, levkivskyi, lovi, rhettinger, stutzbach, xtreak
Priority: normal Keywords:

Created on 2019-12-14 10:04 by Zac Hatfield-Dodds, last changed 2020-10-22 14:08 by Zac Hatfield-Dodds. This issue is now closed.

Messages (3)
msg358386 - (view) Author: Zac Hatfield-Dodds (Zac Hatfield-Dodds) * Date: 2019-12-14 10:04
>>> from collections.abc import Hashable, Reversible
>>> assert issubclass(Reversible, Hashable)

However, this is trivially wrong - lists are Reversible but not Hashable, and there is no reason to thing that reversible objects should all be hashable.

The versions of these classes in the typing module have the same problem.
msg358397 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2019-12-14 15:48
I don't know that this is easily solved. By design, issubclass(X, Hashable) checks whether X defines a __hash__ method (or at least has a class attribute __hash__ that isn't None). And because everything ultimately derives from object, which *does* have a __hash__ method (that just hashes the object's address), everything appears hashable, *except* if it explicitly sets __hash__ = None.

You'll find that many classes defined in collections.abc are hashable (e.g. Iterable, Iterator, Sequence, Collection).

But not Set and Mapping. This is because those override __eq__, and there's some deep magic somewhere that sets __hash__ = None in the class dict if __eq__ is overridden.

You could try the following: add an explicit __hash__ = None to all the collection ABCs (in _collections_abc.py) that you think shouldn't define __hash__, and see if all the tests pass. 

However, even if they do, I suspect that this may break stuff. E.g. a class that inherits from Iterable but doesn't override __hash__ or __eq__ would suddenly no longer be usable as a dict key.

Since this is only a problem with abstract classes like Iterable or Reversible, maybe we should just ignore the problem?
msg379294 - (view) Author: Zac Hatfield-Dodds (Zac Hatfield-Dodds) * Date: 2020-10-22 14:08
I'm closing this as not-a-bug.

The way protocols just check methods does make sense (thanks for your comment Guido!), and a later refactoring of the code that prompted this issue (to deal only in concrete classes) dissolved the problem.
History
Date User Action Args
2020-10-22 14:08:36Zac Hatfield-Doddssetstatus: open -> closed
resolution: not a bug
messages: + msg379294

stage: resolved
2019-12-20 18:49:45levkivskyisetnosy: + levkivskyi
2019-12-14 15:48:11gvanrossumsetnosy: + gvanrossum
messages: + msg358397
2019-12-14 12:22:03xtreaksetnosy: + xtreak
2019-12-14 12:05:04lovisetnosy: + lovi

versions: - Python 3.7, Python 3.8
2019-12-14 12:02:49SilentGhostsetnosy: + rhettinger, stutzbach

versions: - Python 3.6
2019-12-14 10:04:07Zac Hatfield-Doddscreate