Deep Dive into Metaclasses and Class Creation

60 mintext

Theory & Concepts

Introduction to Metaclasses

Metaclasses are one of Python's most powerful and misunderstood features. They allow you to control how classes themselves are created, going beyond what decorators and inheritance can achieve.

What Are Metaclasses?

💡 Core Concept: In Python, everything is an object - including classes. Metaclasses are the "classes of classes" - they define how classes behave.

The Type Hierarchy:

object → instance of → class → instance of → metaclass → instance of → type

When you write:

python
class MyClass:
pass

Python actually does:

  1. Looks for a metaclass (defaults to type)
  2. Calls the metaclass to create the class
  3. The metaclass returns the new class object

Why Learn Metaclasses?

Real-World Applications:

  • ORM Frameworks: Django and SQLAlchemy use metaclasses to map classes to database tables
  • Validation Frameworks: Pydantic uses metaclasses for data validation
  • API Frameworks: FastAPI uses metaclasses for automatic serialization
  • Singleton Pattern: Enforcing single instance classes
  • Plugin Systems: Automatic registration of plugins
  • Abstract Base Classes: The abc module uses metaclasses

⚠️ Important: Tim Peters (Python core developer) said: "Metaclasses are deeper magic than 99% of users should ever worry about. If you wonder whether you need them, you don't."

However, understanding metaclasses makes you a better Python developer and helps you understand how frameworks work under the hood.

Understanding type - The Default Metaclass

The built-in type is the default metaclass for all classes in Python.

type as a Function (Runtime Class Creation)

type can be used in two ways:

1. Get the type of an object:

python
x = 5
print(type(x)) # <class 'int'>

2. Create a class dynamically:

python
# type(name, bases, dict)
MyClass = type('MyClass', (), {'x': 5})
# Equivalent to:
class MyClass:
x = 5

How Classes Are Created

When Python encounters a class definition, it:

  1. Collects the class body into a dictionary
  2. Determines the metaclass (type by default)
  3. Calls the metaclass with (name, bases, namespace)
  4. Returns the class object
python
# These are equivalent:
# Traditional syntax
class Dog:
def bark(self):
return "Woof!"
# Using type directly
Dog = type('Dog', (), {
'bark': lambda self: "Woof!"
})

Creating Custom Metaclasses

A metaclass is a class that inherits from type and overrides specific methods.

The Metaclass Lifecycle

Key methods to override:

  1. __new__(mcs, name, bases, namespace)

    • Called to create the class object
    • Can modify class attributes before creation
    • Must return the class object
  2. __init__(cls, name, bases, namespace)

    • Called to initialize the class object
    • Can't change the class structure
    • Used for validation and setup
  3. __call__(cls, *args, **kwargs)

    • Called when the class is instantiated
    • Controls how instances are created
    • Useful for singletons and object pools

Basic Metaclass Example

python
class Meta(type):
def __new__(mcs, name, bases, namespace):
print(f"Creating class {name}")
return super().__new__(mcs, name, bases, namespace)
def __init__(cls, name, bases, namespace):
print(f"Initializing class {name}")
super().__init__(name, bases, namespace)
class MyClass(metaclass=Meta):
pass
# Output when class is defined:
# Creating class MyClass
# Initializing class MyClass

Practical Metaclass Patterns

1. Automatic Registration Pattern

Register all subclasses automatically:

python
class PluginRegistry(type):
plugins = []
def __new__(mcs, name, bases, namespace):
cls = super().__new__(mcs, name, bases, namespace)
if name != 'Plugin': # Don't register base class
mcs.plugins.append(cls)
return cls
class Plugin(metaclass=PluginRegistry):
pass
class PDFPlugin(Plugin):
pass
class ImagePlugin(Plugin):
pass
print(PluginRegistry.plugins)
# [<class 'PDFPlugin'>, <class 'ImagePlugin'>]

2. Singleton Pattern

Ensure only one instance exists:

python
class SingletonMeta(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
instance = super().__call__(*args, **kwargs)
cls._instances[cls] = instance
return cls._instances[cls]
class Database(metaclass=SingletonMeta):
def __init__(self):
self.connection = "Connected"
db1 = Database()
db2 = Database()
print(db1 is db2) # True - same instance

3. Validation and Enforcement

Enforce class structure rules:

python
class RequiredMethodsMeta(type):
required_methods = ['save', 'load']
def __new__(mcs, name, bases, namespace):
# Skip validation for base class
if name != 'Model':
for method in mcs.required_methods:
if method not in namespace:
raise TypeError(
f"Class {name} must implement '{method}' method"
)
return super().__new__(mcs, name, bases, namespace)
class Model(metaclass=RequiredMethodsMeta):
pass
class UserModel(Model):
def save(self):
print("Saving user...")
def load(self):
print("Loading user...")
# This would raise TypeError:
# class BrokenModel(Model):
# pass # Missing save() and load()

4. Automatic Property Creation

Convert attributes to properties automatically:

python
class AutoPropertyMeta(type):
def __new__(mcs, name, bases, namespace):
# Find attributes that should be properties
for attr_name, attr_value in list(namespace.items()):
if not attr_name.startswith('_') and not callable(attr_value):
# Create private attribute
private_name = f'_{attr_name}'
namespace[private_name] = attr_value
# Create property
namespace[attr_name] = property(
lambda self, n=private_name: getattr(self, n),
lambda self, value, n=private_name: setattr(self, n, value)
)
return super().__new__(mcs, name, bases, namespace)
class Person(metaclass=AutoPropertyMeta):
name = ""
age = 0
p = Person()
p.name = "Alice"
print(p.name) # Works as a property

5. ORM-Style Field Validation

Similar to Django/SQLAlchemy:

python
class Field:
def __init__(self, field_type):
self.field_type = field_type
def validate(self, value):
if not isinstance(value, self.field_type):
raise TypeError(
f"Expected {self.field_type.__name__}, "
f"got {type(value).__name__}"
)
class ModelMeta(type):
def __new__(mcs, name, bases, namespace):
# Collect field definitions
fields = {}
for key, value in list(namespace.items()):
if isinstance(value, Field):
fields[key] = value
namespace['_fields'] = fields
# Create __init__ that validates fields
def __init__(self, **kwargs):
for field_name, field in self._fields.items():
value = kwargs.get(field_name)
if value is not None:
field.validate(value)
setattr(self, field_name, value)
namespace['__init__'] = __init__
return super().__new__(mcs, name, bases, namespace)
class User(metaclass=ModelMeta):
name = Field(str)
age = Field(int)
user = User(name="Alice", age=30)
print(user.name, user.age) # Alice 30
# This would raise TypeError:
# user = User(name="Bob", age="thirty")

Advanced Metaclass Concepts

Metaclass Inheritance

Metaclasses can inherit from each other:

python
class BaseMeta(type):
def __new__(mcs, name, bases, namespace):
namespace['created_by'] = 'BaseMeta'
return super().__new__(mcs, name, bases, namespace)
class ExtendedMeta(BaseMeta):
def __new__(mcs, name, bases, namespace):
namespace['extended_by'] = 'ExtendedMeta'
return super().__new__(mcs, name, bases, namespace)
class MyClass(metaclass=ExtendedMeta):
pass
print(MyClass.created_by) # BaseMeta
print(MyClass.extended_by) # ExtendedMeta

Multiple Metaclasses (Metaclass Conflict)

When inheriting from classes with different metaclasses, Python requires a common metaclass:

python
class Meta1(type):
pass
class Meta2(type):
pass
class A(metaclass=Meta1):
pass
class B(metaclass=Meta2):
pass
# This causes metaclass conflict:
# class C(A, B):
# pass
# Solution: Create a metaclass that inherits from both
class Meta3(Meta1, Meta2):
pass
class C(A, B, metaclass=Meta3):
pass

__prepare__ Method

Controls the namespace dictionary used for the class:

python
class OrderedMeta(type):
@classmethod
def __prepare__(mcs, name, bases):
# Return OrderedDict to preserve attribute order
from collections import OrderedDict
return OrderedDict()
def __new__(mcs, name, bases, namespace):
# namespace is now an OrderedDict
print(f"Attributes in order: {list(namespace.keys())}")
return super().__new__(mcs, name, bases, dict(namespace))
class MyClass(metaclass=OrderedMeta):
z = 1
a = 2
m = 3
# Output: Attributes in order: ['__module__', '__qualname__', 'z', 'a', 'm']

Metaclasses vs Alternatives

When to Use Each Approach

| Pattern | Use When | Example | |---------|----------|---------| | Metaclass | Need to control class creation itself | ORM models, ABCs, singletons | | Class Decorator | Need to modify class after creation | Adding methods, wrapping | | __init_subclass__ | Need to customize subclasses (Python 3.6+) | Simpler than metaclasses | | Descriptor | Need to control attribute access | Properties, validators |

__init_subclass__ Alternative (Simpler!)

Python 3.6+ introduced a simpler alternative for many metaclass use cases:

python
class PluginBase:
plugins = []
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
cls.plugins.append(cls)
class PDFPlugin(PluginBase):
pass
class ImagePlugin(PluginBase):
pass
print(PluginBase.plugins)
# [<class 'PDFPlugin'>, <class 'ImagePlugin'>]

Class Decorators Alternative

For post-creation modification:

python
def add_timestamp(cls):
cls.created_at = datetime.now()
return cls
@add_timestamp
class MyClass:
pass
print(MyClass.created_at)

Common Metaclass Pitfalls

Mistake 1: Overcomplicating Simple Tasks

python
# ❌ Wrong - Metaclass overkill
class AddMethodMeta(type):
def __new__(mcs, name, bases, namespace):
namespace['get_name'] = lambda self: self.name
return super().__new__(mcs, name, bases, namespace)
# ✅ Correct - Use class decorator or inheritance
def add_get_name(cls):
cls.get_name = lambda self: self.name
return cls

Mistake 2: Modifying __init__ Instead of __new__

python
# ❌ Wrong - Can't change class structure in __init__
class WrongMeta(type):
def __init__(cls, name, bases, namespace):
cls.new_attr = "value" # Too late!
super().__init__(name, bases, namespace)
# ✅ Correct - Modify in __new__
class RightMeta(type):
def __new__(mcs, name, bases, namespace):
namespace['new_attr'] = "value"
return super().__new__(mcs, name, bases, namespace)

Mistake 3: Not Calling super()

python
# ❌ Wrong - Breaks inheritance chain
class BadMeta(type):
def __new__(mcs, name, bases, namespace):
return type.__new__(mcs, name, bases, namespace) # Skip super()
# ✅ Correct - Always use super()
class GoodMeta(type):
def __new__(mcs, name, bases, namespace):
return super().__new__(mcs, name, bases, namespace)

Real-World Example: Building a Simple ORM

Let's build a mini ORM to understand how Django/SQLAlchemy work:

python
class Field:
def __init__(self, field_type, required=True):
self.field_type = field_type
self.required = required
class ModelMeta(type):
def __new__(mcs, name, bases, namespace):
# Skip for base Model class
if name == 'Model':
return super().__new__(mcs, name, bases, namespace)
# Collect fields
fields = {}
for key, value in list(namespace.items()):
if isinstance(value, Field):
fields[key] = value
del namespace[key] # Remove field descriptors
namespace['_fields'] = fields
namespace['_table_name'] = name.lower()
# Add save method
def save(self):
field_values = {
name: getattr(self, name, None)
for name in self._fields
}
print(f"INSERT INTO {self._table_name} {field_values}")
namespace['save'] = save
return super().__new__(mcs, name, bases, namespace)
class Model(metaclass=ModelMeta):
def __init__(self, **kwargs):
for name, field in self._fields.items():
value = kwargs.get(name)
if value is None and field.required:
raise ValueError(f"{name} is required")
setattr(self, name, value)
class User(Model):
name = Field(str)
email = Field(str)
age = Field(int, required=False)
user = User(name="Alice", email="alice@example.com")
user.save()
# Output: INSERT INTO user {'name': 'Alice', 'email': 'alice@example.com', 'age': None}

Summary

Key Takeaways:

  • Metaclasses control how classes are created, not instances
  • type is the default metaclass for all classes
  • Three key methods: __new__, __init__, __call__
  • Use cases: ORMs, validation, singletons, plugin systems
  • Alternatives: __init_subclass__, decorators, descriptors
  • Best practice: Use simpler alternatives when possible

Metaclass Workflow:

  1. Python collects class body → dictionary
  2. Determines metaclass (explicit or inherited)
  3. Calls metaclass.__new__() to create class
  4. Calls metaclass.__init__() to initialize class
  5. Returns class object

When to Use Metaclasses:

  • ✅ Building frameworks (ORMs, APIs)
  • ✅ Enforcing API contracts
  • ✅ Automatic registration
  • ✅ Class-level validation
  • ❌ Simple attribute addition (use decorators)
  • ❌ Instance behavior (use __init__)

Best Practices:

  • Always call super() in metaclass methods
  • Use __init_subclass__ for simpler cases (Python 3.6+)
  • Document metaclass behavior clearly
  • Provide good error messages
  • Consider if a decorator would work instead

💡 Final Tip: Master metaclasses to understand Python deeply, but use them sparingly in production code. Most problems have simpler solutions!

Lesson Content

Master Python's metaclasses and understand how classes are created at runtime. Learn to control class instantiation, customize attribute access, and implement powerful metaprogramming patterns.

Code Example

python
"""
Deep Dive into Metaclasses and Class Creation
This module demonstrates advanced metaclass concepts with production-ready examples.
Metaclasses control how classes are created - they are the "classes of classes".
"""
from typing import Dict, Any, Type, List
from abc import ABCMeta
from datetime import datetime
from collections import OrderedDict
# ============================================
# PART 1: UNDERSTANDING TYPE AND CLASS CREATION
# ============================================
def demonstrate_type_as_factory():
"""Show how type() creates classes dynamically."""
print("="*60)
print("PART 1: Creating Classes with type()")
print("="*60)
# Method 1: Traditional class definition
class Dog:
species = "Canis familiaris"
def __init__(self, name):
self.name = name
def bark(self):
return f"{self.name} says Woof!"
# Method 2: Using type() - equivalent to above
def bark_method(self):
return f"{self.name} says Woof!"
DogDynamic = type(
'DogDynamic', # Class name
(), # Base classes (tuple)
{ # Class namespace (dict)
'species': 'Canis familiaris',
'__init__': lambda self, name: setattr(self, 'name', name),
'bark': bark_method
}
)
# Both work identically
dog1 = Dog("Buddy")
dog2 = DogDynamic("Max")
print(f"Traditional: {dog1.bark()}")
print(f"Dynamic: {dog2.bark()}")
print(f"Both are classes: {type(dog1).__name__}, {type(dog2).__name__}")
# ============================================
# PART 2: BASIC METACLASS
# ============================================
class DebugMeta(type):
"""Metaclass that logs class creation process."""
def __new__(mcs, name, bases, namespace):
"""
Called to CREATE the class object.
Args:
mcs: The metaclass itself
name: Name of the class being created
bases: Tuple of base classes
namespace: Dictionary of class attributes
"""
print(f"
[DebugMeta.__new__] Creating class: {name}")
print(f" Bases: {bases}")
print(f" Attributes: {list(namespace.keys())}")
# Create the class
cls = super().__new__(mcs, name, bases, namespace)
# Add timestamp to all classes
cls._created_at = datetime.now()
return cls
def __init__(cls, name, bases, namespace):
"""
Called to INITIALIZE the class object.
Args:
cls: The class that was just created
name: Name of the class
bases: Tuple of base classes
namespace: Dictionary of class attributes
"""
print(f"[DebugMeta.__init__] Initializing class: {name}")
super().__init__(name, bases, namespace)
def __call__(cls, *args, **kwargs):
"""
Called when the class is INSTANTIATED.
Args:
cls: The class being instantiated
*args, **kwargs: Arguments passed to __init__
"""
print(f"[DebugMeta.__call__] Creating instance of {cls.__name__}")
instance = super().__call__(*args, **kwargs)
print(f"[DebugMeta.__call__] Instance created: {instance}")
return instance
class DebuggedClass(metaclass=DebugMeta):
"""A class using the debug metaclass."""
def __init__(self, value):
self.value = value
def __repr__(self):
return f"DebuggedClass(value={self.value})"
# ============================================
# PART 3: SINGLETON PATTERN WITH METACLASS
# ============================================
class SingletonMeta(type):
"""
Metaclass that implements the Singleton pattern.
Ensures only one instance of a class exists.
"""
_instances: Dict[Type, Any] = {}
def __call__(cls, *args, **kwargs):
"""Return existing instance or create new one."""
if cls not in cls._instances:
# Create new instance
instance = super().__call__(*args, **kwargs)
cls._instances[cls] = instance
print(f"Created new {cls.__name__} instance")
else:
print(f"Returning existing {cls.__name__} instance")
return cls._instances[cls]
class DatabaseConnection(metaclass=SingletonMeta):
"""Database connection that should be singleton."""
def __init__(self, host="localhost", port=5432):
self.host = host
self.port = port
print(f"Connecting to {host}:{port}...")
def query(self, sql):
return f"Executing: {sql}"
# ============================================
# PART 4: AUTOMATIC PLUGIN REGISTRATION
# ============================================
class PluginRegistry(type):
"""
Metaclass that automatically registers all plugin classes.
Useful for plugin systems and frameworks.
"""
plugins: List[Type] = []
def __new__(mcs, name, bases, namespace):
cls = super().__new__(mcs, name, bases, namespace)
# Register plugin (skip base class)
if name != 'Plugin':
mcs.plugins.append(cls)
print(f"Registered plugin: {name}")
return cls
@classmethod
def get_plugins(mcs):
"""Return all registered plugins."""
return mcs.plugins
@classmethod
def get_plugin(mcs, name):
"""Get plugin by name."""
for plugin in mcs.plugins:
if plugin.__name__ == name:
return plugin
return None
class Plugin(metaclass=PluginRegistry):
"""Base class for all plugins."""
def execute(self):
raise NotImplementedError
class PDFExportPlugin(Plugin):
"""Plugin for exporting to PDF."""
def execute(self):
return "Exporting to PDF..."
class CSVExportPlugin(Plugin):
"""Plugin for exporting to CSV."""
def execute(self):
return "Exporting to CSV..."
class ImageProcessorPlugin(Plugin):
"""Plugin for processing images."""
def execute(self):
return "Processing images..."
# ============================================
# PART 5: VALIDATION AND ENFORCEMENT
# ============================================
class InterfaceEnforcerMeta(type):
"""
Metaclass that enforces interface implementation.
Similar to abstract base classes but with custom logic.
"""
required_methods = ['save', 'load', 'validate']
def __new__(mcs, name, bases, namespace):
# Skip validation for base class
if name == 'Model':
return super().__new__(mcs, name, bases, namespace)
# Check for required methods
missing_methods = []
for method in mcs.required_methods:
if method not in namespace:
# Check if method is in base classes
has_method = any(hasattr(base, method) for base in bases)
if not has_method:
missing_methods.append(method)
if missing_methods:
raise TypeError(
f"Class '{name}' must implement these methods: "
f"{', '.join(missing_methods)}"
)
return super().__new__(mcs, name, bases, namespace)
class Model(metaclass=InterfaceEnforcerMeta):
"""Base model class with required interface."""
pass
class UserModel(Model):
"""User model with all required methods."""
def __init__(self, name, email):
self.name = name
self.email = email
def save(self):
print(f"Saving user: {self.name}")
def load(self):
print(f"Loading user: {self.name}")
def validate(self):
if '@' not in self.email:
raise ValueError("Invalid email")
print(f"User {self.name} is valid")
# ============================================
# PART 6: ORM-STYLE FIELD VALIDATION
# ============================================
class Field:
"""Base field class for ORM."""
def __init__(self, field_type, required=True, default=None):
self.field_type = field_type
self.required = required
self.default = default
def validate(self, value):
"""Validate field value."""
if value is None:
if self.required:
raise ValueError(f"Field is required")
return self.default
if not isinstance(value, self.field_type):
raise TypeError(
f"Expected {self.field_type.__name__}, "
f"got {type(value).__name__}"
)
return value
class ORMMeta(type):
"""
Metaclass for ORM models.
Automatically handles field validation and provides ORM functionality.
"""
def __new__(mcs, name, bases, namespace):
# Skip for base class
if name == 'ORMModel':
return super().__new__(mcs, name, bases, namespace)
# Collect field definitions
fields = {}
for key, value in list(namespace.items()):
if isinstance(value, Field):
fields[key] = value
# Remove field descriptors from class
del namespace[key]
namespace['_fields'] = fields
namespace['_table_name'] = name.lower()
# Create custom __init__
def __init__(self, **kwargs):
"""Initialize model with field validation."""
for field_name, field in self._fields.items():
value = kwargs.get(field_name)
validated_value = field.validate(value)
setattr(self, field_name, validated_value)
namespace['__init__'] = __init__
# Add ORM methods
def save(self):
"""Save model to database (simulated)."""
field_values = {
name: getattr(self, name, None)
for name in self._fields
}
print(f"INSERT INTO {self._table_name} {field_values}")
def to_dict(self):
"""Convert model to dictionary."""
return {
name: getattr(self, name, None)
for name in self._fields
}
namespace['save'] = save
namespace['to_dict'] = to_dict
return super().__new__(mcs, name, bases, namespace)
class ORMModel(metaclass=ORMMeta):
"""Base class for ORM models."""
pass
class User(ORMModel):
"""User ORM model with field validation."""
name = Field(str)
email = Field(str)
age = Field(int, required=False, default=0)
class Product(ORMModel):
"""Product ORM model."""
title = Field(str)
price = Field(float)
quantity = Field(int)
# ============================================
# PART 7: ATTRIBUTE TRACKING AND MODIFICATION
# ============================================
class AttributeTrackerMeta(type):
"""
Metaclass that tracks attribute modifications.
Useful for change detection and audit trails.
"""
def __new__(mcs, name, bases, namespace):
# Add tracking wrapper to all methods
for key, value in namespace.items():
if callable(value) and not key.startswith('_'):
namespace[key] = mcs._track_calls(value, key)
cls = super().__new__(mcs, name, bases, namespace)
# Add tracking list
cls._method_calls = []
return cls
@staticmethod
def _track_calls(method, method_name):
"""Wrap method to track calls."""
def wrapper(self, *args, **kwargs):
call_info = {
'method': method_name,
'args': args,
'kwargs': kwargs,
'timestamp': datetime.now()
}
self._method_calls.append(call_info)
return method(self, *args, **kwargs)
return wrapper
class TrackedCalculator(metaclass=AttributeTrackerMeta):
"""Calculator with method call tracking."""
def add(self, a, b):
return a + b
def multiply(self, a, b):
return a * b
def get_history(self):
"""Get call history."""
return self._method_calls
# ============================================
# PART 8: ORDERED ATTRIBUTES WITH __prepare__
# ============================================
class OrderedClassMeta(type):
"""
Metaclass that preserves attribute definition order.
Useful for form fields, schema definitions, etc.
"""
@classmethod
def __prepare__(mcs, name, bases):
"""Return OrderedDict for namespace."""
return OrderedDict()
def __new__(mcs, name, bases, namespace):
# namespace is now an OrderedDict
cls = super().__new__(mcs, name, bases, dict(namespace))
# Store field order
cls._field_order = [
key for key in namespace.keys()
if not key.startswith('_')
]
return cls
class OrderedForm(metaclass=OrderedClassMeta):
"""Form with preserved field order."""
username = "string"
email = "email"
password = "password"
age = "integer"
country = "select"
# ============================================
# PART 9: COMBINING MULTIPLE METACLASSES
# ============================================
class LoggingMeta(type):
"""Metaclass that adds logging."""
def __new__(mcs, name, bases, namespace):
cls = super().__new__(mcs, name, bases, namespace)
cls._log = []
return cls
class ValidationMeta(type):
"""Metaclass that adds validation."""
def __new__(mcs, name, bases, namespace):
cls = super().__new__(mcs, name, bases, namespace)
cls._validated = True
return cls
class CombinedMeta(LoggingMeta, ValidationMeta):
"""Combined metaclass inheriting from both."""
def __new__(mcs, name, bases, namespace):
return super().__new__(mcs, name, bases, namespace)
class CombinedClass(metaclass=CombinedMeta):
"""Class using combined metaclass."""
pass
# ============================================
# DEMONSTRATION FUNCTIONS
# ============================================
def demo_basic_metaclass():
"""Demonstrate basic metaclass usage."""
print("
" + "="*60)
print("DEMO: Basic Metaclass")
print("="*60)
# Class creation triggers __new__ and __init__
obj = DebuggedClass(42)
print(f"
Created at: {DebuggedClass._created_at}")
def demo_singleton():
"""Demonstrate singleton pattern."""
print("
" + "="*60)
print("DEMO: Singleton Pattern")
print("="*60)
db1 = DatabaseConnection("localhost", 5432)
db2 = DatabaseConnection("remote", 3306) # Same instance!
print(f"
Same instance? {db1 is db2}")
print(f"Host: {db1.host}, Port: {db1.port}")
def demo_plugin_system():
"""Demonstrate plugin registration."""
print("
" + "="*60)
print("DEMO: Plugin Registration System")
print("="*60)
print(f"
Registered plugins: {len(PluginRegistry.get_plugins())}")
for plugin in PluginRegistry.get_plugins():
instance = plugin()
print(f" - {plugin.__name__}: {instance.execute()}")
def demo_orm():
"""Demonstrate ORM functionality."""
print("
" + "="*60)
print("DEMO: ORM with Field Validation")
print("="*60)
# Create user
user = User(name="Alice", email="alice@example.com", age=30)
print(f"
User created: {user.to_dict()}")
user.save()
# Create product
product = Product(title="Laptop", price=999.99, quantity=10)
print(f"
Product created: {product.to_dict()}")
product.save()
# Validation error example
try:
invalid_user = User(name="Bob", email=123) # Wrong type
except TypeError as e:
print(f"
Validation error: {e}")
def demo_attribute_tracking():
"""Demonstrate attribute tracking."""
print("
" + "="*60)
print("DEMO: Attribute Tracking")
print("="*60)
calc = TrackedCalculator()
result1 = calc.add(5, 3)
result2 = calc.multiply(4, 7)
result3 = calc.add(10, 20)
print(f"
Results: {result1}, {result2}, {result3}")
print(f"
Method call history:")
for call in calc.get_history():
print(f" - {call['method']}{call['args']} at {call['timestamp']}")
def demo_ordered_attributes():
"""Demonstrate ordered attributes."""
print("
" + "="*60)
print("DEMO: Ordered Attributes")
print("="*60)
print(f"
Field order: {OrderedForm._field_order}")
print("
Fields in definition order:")
for field in OrderedForm._field_order:
value = getattr(OrderedForm, field)
print(f" - {field}: {value}")
# ============================================
# MAIN EXECUTION
# ============================================
if __name__ == "__main__":
print("
" + "="*60)
print("METACLASSES: DEEP DIVE DEMONSTRATION")
print("="*60)
# Run all demonstrations
demonstrate_type_as_factory()
demo_basic_metaclass()
demo_singleton()
demo_plugin_system()
demo_orm()
demo_attribute_tracking()
demo_ordered_attributes()
print("
" + "="*60)
print("✅ All demonstrations completed!")
print("="*60)
# ============================================
# KEY TAKEAWAYS
# ============================================
"""
METACLASS PATTERNS DEMONSTRATED:
1. Type as Factory (demonstrate_type_as_factory)
- Creating classes dynamically with type()
2. Debug Metaclass (DebugMeta)
- Logging class creation, initialization, and instantiation
3. Singleton Pattern (SingletonMeta)
- Ensuring only one instance exists
4. Plugin Registry (PluginRegistry)
- Automatic registration of subclasses
5. Interface Enforcement (InterfaceEnforcerMeta)
- Validating required methods at class creation
6. ORM Pattern (ORMMeta)
- Field validation and database abstraction
7. Attribute Tracking (AttributeTrackerMeta)
- Monitoring method calls and changes
8. Ordered Attributes (OrderedClassMeta)
- Preserving definition order with __prepare__
9. Multiple Inheritance (CombinedMeta)
- Combining multiple metaclasses
BEST PRACTICES:
- Always call super() in metaclass methods
- Use __init_subclass__ for simpler cases (Python 3.6+)
- Document metaclass behavior clearly
- Provide meaningful error messages
- Consider if a decorator would suffice
"""
Section 1 of 12 • Lesson 1 of 37