Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
__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.
