Your example sounds like an abstract class. You could define an abstract class, and add a type annotation for that parameter or explicitly check its type:
from abc import ABC, abstractmethod
class MyABC(ABC):
@abstractmethod
def fly(self):
pass
@abstractmethod
def eat(self):
pass
@abstractmethod
def dance(self):
pass
And for your method:
def test(param: MyABC):
if not isinstance(param, MyABC):
raise Exception("param must inherit MyABC.")
This works because when passing param
to test
method, it must inherit MyABC
- and in order to inherit MyABC
, the class must define the three methods fly
, eat
, dance
- otherwise, a TypeError
would be raised when trying to instantiate it.
Edit:
If you want the subclasses not to directly inherit but still "count as" a MyABC
subclass, you can use __subclasshook__
:
from abc import ABC, abstractmethod
class MyABC(ABC):
@abstractmethod
def fly(self):
pass
@abstractmethod
def eat(self):
pass
@abstractmethod
def dance(self):
pass
@classmethod
def __subclasshook__(cls, C):
if any("fly" in B.__dict__ for B in C.__mro__):
# add checks for dance and eat...
return True
return NotImplemented
Now every class that implements the fly
method (or inherits a class that implements it) will return True
to the following condition:
isinstance(CLASS, MyABC)
From Fluent Python:
The subclasshook adds some duck typing DNA to the whole goose typing proposition. You can have formal interface definitions with ABCs, you can make isinstance checks everywhere, and still have a completely unrelated class play along just because it implements a certain method (or because it does whatever it takes to convince a subclasshook to vouch for it). Of course, this only works for ABCs that do pro‐ vide a subclasshook.