Advanced Class Patterns
Metaclasses, descriptors, and class-level programming.
Overview
Master advanced class patterns.
Metaclasses
class RegistryMeta(type):
_registry = {}
def __new__(cls, name, bases, attrs):
new_class = super().__new__(cls, name, bases, attrs)
if name != 'Base':
cls._registry[name] = new_class
return new_class
@classmethod
def get_registry(cls):
return cls._registry.copy()
class Base(metaclass=RegistryMeta):
pass
class PluginA(Base):
pass
class PluginB(Base):
pass
print(RegistryMeta.get_registry())
Descriptors
class Validated:
def __init__(self, min_value=None, max_value=None):
self.min_value = min_value
self.max_value = max_value
def __set_name__(self, owner, name):
self.name = name
def __get__(self, obj, objtype=None):
if obj is None:
return self
return getattr(obj, f'_{self.name}', None)
def __set__(self, obj, value):
if self.min_value is not None and value < self.min_value:
raise ValueError(f"{self.name} must be >= {self.min_value}")
if self.max_value is not None and value > self.max_value:
raise ValueError(f"{self.name} must be <= {self.max_value}")
setattr(obj, f'_{self.name}', value)
class Product:
price = Validated(min_value=0)
quantity = Validated(min_value=0, max_value=1000)
def __init__(self, name, price, quantity):
self.name = name
self.price = price
self.quantity = quantity
p = Product("Widget", 9.99, 100)
print(p.price) # 9.99
# p.price = -5 # ValueError
Practice
Create a metaclass that adds logging to all methods.