__subclasscheck__ and __subclasshook__ in Python

Python provides powerful mechanisms for customizing inheritance behavior through two special methods: __subclasscheck__ and __subclasshook__. These methods allow you to define custom criteria for determining subclass relationships beyond traditional inheritance.

Understanding __subclasscheck__ and __subclasshook__

By default, Python's issubclass() function checks the inheritance tree to determine class relationships. However, you can override this behavior using these special methods:

  • __subclasscheck__(cls, subclass) Called by issubclass() to test if a class is a subclass. Can be overridden to provide custom inheritance logic.

  • __subclasshook__(cls, subclass) Defined in abstract base classes (ABCs) to customize subclass checks. Called by the default __subclasscheck__ implementation.

Using __subclasshook__ with Abstract Base Classes

Let's create an abstract base class that defines required methods and uses __subclasshook__ to check for their presence ?

from abc import ABCMeta, abstractmethod

class Shape(metaclass=ABCMeta):
    @abstractmethod
    def area(self):
        pass
    
    @abstractmethod
    def perimeter(self):
        pass

class Circle:
    def __init__(self, radius):
        self.radius = radius
    
    def area(self):
        return 3.14 * self.radius * self.radius
    
    def perimeter(self):
        return 2 * 3.14 * self.radius

print(issubclass(Circle, Shape))
False

Even though Circle implements the required methods, issubclass() returns False because there's no direct inheritance. Now let's add __subclasshook__ to customize this behavior ?

from abc import ABCMeta, abstractmethod

class Shape(metaclass=ABCMeta):
    @abstractmethod
    def area(self):
        pass
    
    @abstractmethod
    def perimeter(self):
        pass
    
    @classmethod
    def __subclasshook__(cls, subclass):
        if cls is Shape:
            if all(hasattr(subclass, method) for method in ['area', 'perimeter']):
                return True
        return NotImplemented

class Circle:
    def __init__(self, radius):
        self.radius = radius
    
    def area(self):
        return 3.14 * self.radius * self.radius
    
    def perimeter(self):
        return 2 * 3.14 * self.radius

print(issubclass(Circle, Shape))
True

Using __subclasscheck__ for Custom Logic

You can override __subclasscheck__ directly for more fine-grained control over inheritance testing ?

class CustomBase(type):
    def __subclasscheck__(cls, subclass):
        return (hasattr(subclass, "magic_method") and 
                callable(getattr(subclass, "magic_method")))

class MyBase(metaclass=CustomBase):
    pass

class ClassWithMagic:
    def magic_method(self):
        return "I have magic!"

class ClassWithoutMagic:
    def regular_method(self):
        return "No magic here"

print(issubclass(ClassWithMagic, MyBase))
print(issubclass(ClassWithoutMagic, MyBase))
True
False

Comparison

Method Used In Best For
__subclasshook__ Abstract Base Classes Protocol enforcement
__subclasscheck__ Metaclasses Custom inheritance logic

Practical Use Cases

  • Protocol enforcement Ensure classes implement specific methods or attributes without requiring direct inheritance.

  • Duck typing validation Check if a class behaves like a certain type based on available methods rather than inheritance.

  • Loose coupling Create flexible relationships between classes without rigid inheritance hierarchies.

Conclusion

The __subclasscheck__ and __subclasshook__ methods provide powerful ways to customize Python's inheritance behavior. Use __subclasshook__ in abstract base classes for protocol enforcement, and __subclasscheck__ for more complex custom inheritance logic.

Updated on: 2026-03-27T06:23:49+05:30

1K+ Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements