Lesson 24 · Python standard library deep dive
Python abc & inspect Explained: Abstract Classes & Introspection | Standard Library #24
Video twenty-four of the twenty-five-part series: abc, for abstract base classes, and inspect, for runtime introspection. Abstract methods, abstract…
- CoursePython standard library deep dive
- Lesson24 of 24
- Video18 min
- FormatJupyter notebook · 10 code cells
What you'll learn
- Why Abstract Base Classes, and ABC Basics
- @abstractmethod - Enforcing Subclass Implementation
- ABC with Concrete Helper Methods (Template Method Pattern)
- Abstract Properties
- isinstance/issubclass and Virtual Subclasses with register()
- inspect.signature() - Examining Function Signatures
- inspect.getmembers() and getsource()
- inspect.isfunction(), isclass(), ismethod()
Data
No separate download needed — the notebook creates or downloads everything it uses.
📓 Full notebook
Download .ipynbPython Standard Library Deep-Dive, Video 24: abc and inspect#
- Video twenty-four of the twenty-five-part series: abc, for abstract base classes, and inspect, for runtime introspection.
- Abstract methods, abstract properties, virtual subclasses, signatures, source inspection, and the call stack.
- Let's get into it.
Part 1: Why Abstract Base Classes, and ABC Basics#
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
try:
Shape()
except TypeError as e:
print(f'caught: {e}')
Part 2: @abstractmethod - Enforcing Subclass Implementation#
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14159 * self.radius ** 2
c = Circle(3)
print(c.area())
class Incomplete(Shape):
pass
try:
Incomplete()
except TypeError as e:
print(f'caught: {e}')
Part 3: ABC with Concrete Helper Methods (Template Method Pattern)#
class Shape2(ABC):
@abstractmethod
def area(self):
pass
def describe(self):
return f'This shape has an area of {self.area():.2f}'
class Square(Shape2):
def __init__(self, side):
self.side = side
def area(self):
return self.side ** 2
sq = Square(4)
print(sq.describe())
Part 4: Abstract Properties#
class Vehicle(ABC):
@property
@abstractmethod
def wheels(self):
pass
class Car(Vehicle):
@property
def wheels(self):
return 4
car = Car()
print(car.wheels)
try:
car.wheels = 6
except AttributeError as e:
print(f'caught: {e}')
Part 5: isinstance/issubclass and Virtual Subclasses with register()#
class Flyer(ABC):
@abstractmethod
def fly(self):
pass
class Drone:
def fly(self):
return 'buzzing off'
print(isinstance(Drone(), Flyer))
Flyer.register(Drone)
print(isinstance(Drone(), Flyer))
print(issubclass(Drone, Flyer))
Part 6: inspect.signature() - Examining Function Signatures#
import inspect
def greet(name: str, greeting: str = 'Hello', *, shout: bool = False) -> str:
result = f'{greeting}, {name}!'
return result.upper() if shout else result
sig = inspect.signature(greet)
print(sig)
for param_name, param in sig.parameters.items():
print(param_name, param.default, param.annotation)
Part 7: inspect.getmembers() and getsource()#
class Toolbox:
def hammer(self):
pass
def wrench(self):
pass
value = 42
methods = inspect.getmembers(Toolbox, predicate=inspect.isfunction)
print([name for name, _ in methods])
import textwrap
print(inspect.getsource(textwrap.shorten))
Part 8: inspect.isfunction(), isclass(), ismethod()#
def plain_function():
pass
class SampleClass:
def bound_method(self):
pass
instance = SampleClass()
print(inspect.isfunction(plain_function))
print(inspect.isclass(SampleClass))
print(inspect.ismethod(instance.bound_method))
print(inspect.ismethod(plain_function))
print(inspect.ismodule(inspect))
Part 9: inspect.stack() and currentframe() - Call Stack Introspection#
def inner_function():
frame = inspect.currentframe()
print(frame.f_code.co_name)
caller_frame = frame.f_back
print(caller_frame.f_code.co_name)
def outer_function():
inner_function()
outer_function()
def log_caller():
stack = inspect.stack()
print(f'called from: {stack[1].function}')
def some_caller():
log_caller()
some_caller()
Part 10: A Real Pattern - a Plugin System with ABC and inspect#
class Plugin(ABC):
@abstractmethod
def run(self, data):
pass
class UppercasePlugin(Plugin):
def run(self, data):
return data.upper()
class ReversePlugin(Plugin):
def run(self, data):
return data[::-1]
def discover_plugins(module_namespace):
plugins = []
for name, obj in module_namespace.items():
if inspect.isclass(obj) and issubclass(obj, Plugin) and obj is not Plugin:
plugins.append(obj)
return plugins
found = discover_plugins(globals())
print(sorted(p.__name__ for p in found))
for plugin_cls in found:
instance = plugin_cls()
print(f'{plugin_cls.__name__}: {instance.run("hello")}')
Wrap-Up: What You Learned#
- ABC plus @abstractmethod defines a required interface; Python refuses to instantiate a subclass missing any of it.
- A concrete subclass must override every abstract method to become instantiable at all.
- ABCs can mix abstract and concrete methods; a concrete method can call an abstract one, the template method pattern.
- Stacking @property under @abstractmethod requires subclasses to provide an attribute-like value, not just a method.
- register() creates virtual subclasses for isinstance/issubclass checks, with no real inheritance required at all.
- inspect.signature() reveals a callable's parameters, defaults, and annotations without calling it.
- inspect.getmembers()/getsource() list attributes and retrieve real original source code text.
- inspect.isfunction/isclass/ismethod/ismodule are runtime type predicates beyond plain isinstance.
- inspect.stack()/currentframe() introspect the real call stack, discovering callers dynamically.
- A real pattern: an ABC-defined plugin interface, discovered automatically at runtime with inspect.
- That wraps up abc and inspect. Next up: the capstone, a real CLI tool combining everything from this series.
Found this useful?
All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.



