from abc import ABC, abstractmethod class AbstractFoo(ABC): @abstractmethod def calculate_foo(self): pass def foo(self): return self.calculate_foo()
The Abstract class implementation in Python has have a way of determinining what is a child of it even if it’s not a direct subclass of it. This is done by using sub-class hooks. For instance:
class AbstractFoo(ABC): @abstractmethod def calculate_foo(self): pass def foo(self): return self.calculate_foo() @classmethod def __subclasshook__(cls, C): return hasattr(C, "calculate_foo")
True if a class implements
calculate_foo, even if it’s not a sub-class of
class NotAFoo: def calculate_foo(self): print("I can calculate Foo!") isinstance(NotAFoo(), AbstractFoo)
__subclasshook__ can contain any code that can be evaluated at runtime, we can get creative.
For instance, we can create an abstract class for classes that have names like 1960s Frank Zappa albums.
class SixtiesZappa(ABC): @classmethod def __subclasshook__(cls, C): albums = [album.title().replace(" ", "") for album in ["Freak Out", "Absolutely Free", "Lumpy Gravy", "We're Only in It for the Money", "Cruising with Ruben & the Jets", "Mothermania", "Uncle Meat", "Hot Rats"]] name = C.__name__ return name in albums
class HotRats: pass isinstance(HotRats(), SixtiesZappa)
class WeaselsRippedMyFlesh: pass isinstance(WeaselsRippedMyFlesh(), SixtiesZappa)