I'm using version 3.6.3
I'm studying Python collections.abc
's inheritance relationships among classes. And I found some contradictory inheritances among list
, Sequence
and Hashable
As you already know,
1. Sequence
inherits Hashable
class and
2. list
inherits Sequence
from collections import Sequence, Hashable
issubclass(Sequence, Hashable) # 1.
issubclass(list, Sequence) # 2.
True
True
From this, as you can possibly think list
also inherits Hashable
conceptually.
But list
is mutable and it doesn't inherit Hashable
(means 'you cannot 'hash(some_list)')
issubclass(list, Hashable)
False
I think this inheritance is contradictory. I totally understand list
is mutable cause I've used list
hundreds of times but inheritance relationship graph doesn't support this concept. What am I wrong or missing?
I wait for your adivce. Thank you.
So it is actually an interesting design feature, but Python subclasses don't actually need to be transitive. Transitive as defined by Google:
"if a trait is applicable between successive members of a sequence, it must also apply between any two members taken in order. For instance, if A is larger than B, and B is larger than C, then A is larger than C."
For languages where inheritance is transitive, such as Java, if B
inherits A
and C
inherits B
, then C
has to inherit A
. The set of transitive super classes for C
would be A
, B
, and Object
, and the direct super class is B
.
In Python we take a departure from this concept. As you pointed out, Sequence
is Hashable
and a list
is a Sequence
, but a list
is not Hashable
. In fact, list doesn't directly inherit anything (apart from object
which every python class inherits).
# from the PyCharm generated stubs
class list(object):
...
In Python you can use __subclasscheck__
or __subclasshook__
from the metaclass utilities to cause the builtin method issubclass
to do interesting things. A meta class is an advanced language feature used to modify basic rules about how a class operates (modifying how issubclass
works being a great example). Within the abstract base class metaclass ABCMeta
, the __subclasscheck__
method will invoke the __subclasshook__
method on a class if it is defined. You can read a great answer about the uses here.
Certain ABCMeta
classes like Hashable
implement __subclasshook__
to not check an inheritance tree, but to check for the presence of a method. This is helpful such that common contracts don't have to be included in every class definition you make.
For this case, in order to be Hashable
you need to define __hash__
. However, Python states not to hash on a List because it is mutable and therefore it is specifically omitted from this class.
class Hashable(metaclass=ABCMeta):
__slots__ = ()
@abstractmethod
def __hash__(self):
return 0
@classmethod
def __subclasshook__(cls, C):
if cls is Hashable:
return _check_methods(C, "__hash__")
return NotImplemented
class list(object):
...
__hash__ = None
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With