Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Solving inheritance contradictions among abc.Sequence, abc.Hashable and list in Python

Tags:

python

abc

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.

like image 806
Stonehead Avatar asked Oct 16 '22 15:10

Stonehead


1 Answers

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
like image 127
flakes Avatar answered Oct 19 '22 01:10

flakes