Chapter Nine Python Program/Notes¶
Chapter 9 - Meeting Meta Classes¶
The first line of the chapter is “you don’t need to know this”. Anyways here’s what I know.
A class in an object that creates instances.
A metaclass is an object that creates classes.
The base metaclass is a type.
When a class is made the compiler thing checks thr body to see what class attributes are made. This stuff gets put in a dictionary.
__prepare__ can create the namespacve data structure ahead of time I think??
There is no real “final class” in Python, but you can use metaclasses for that.
Metaclasses can obviously have attributes and stuff.
I don’t get ABC’s, so here is what Gemini had to say. An ABC defines what a set of subclasses should do, but it doesn’t necessarily tell them how to do it.
from abc import ABC, abstractmethod
# The Blueprint
class Animal(ABC):
@abstractmethod
def make_sound(self):
pass
def sleep(self):
# ABCs can also have normal methods with logic
print("Zzz...")
# The Implementation
class Dog(Animal):
def make_sound(self):
print("Bark!")
# This would cause an error!
# my_animal = Animal()
# This works perfectly
my_dog = Dog()
my_dog.make_sound() # Output: Bark!
my_dog.sleep() # Output: Zzz...
Why Use an ABC? - Enforced Implementation: It forces any child class to implement specific methods. If the child class forgets one, Python will raise an error the moment you try to use it. - Prevents Instantiation: You cannot create an object directly from an ABC. You can’t have a generic “Shape” object; you must have a “Circle” or a “Square.” - Interface Consistency: It allows you to treat different objects as the same type (Polymorphism) because you are guaranteed they share the same method names. - When you add a __call__ to a class that makes it a function ig. Cuz it functions. - When a class is callable it can be decorated. - You can use a class decorator with parameters. - Singleton
Da Program Example¶
"""
Chapter 9 - Meeting Metaclasses: A Runnable Example
Covers: metaclasses, __prepare__, final classes, ABCs,
__call__, class decorators, and singletons.
"""
from abc import ABC, abstractmethod
from collections import OrderedDict
# ─────────────────────────────────────────────
# 1. THE BASE METACLASS IS `type`
# Every class is secretly an instance of `type`.
# ─────────────────────────────────────────────
print("=== 1. type is the base metaclass ===")
print(type(int)) # <class 'type'>
print(type(str)) # <class 'type'>
class Dog:
pass
print(type(Dog)) # <class 'type'> -- Dog was created by `type`
print()
# ─────────────────────────────────────────────
# 2. CUSTOM METACLASS WITH __prepare__
# __prepare__ lets us supply a custom namespace
# (dict) before the class body is executed.
# Here we use OrderedDict so attribute insertion
# order is guaranteed and visible.
# ─────────────────────────────────────────────
print("=== 2. Custom metaclass with __prepare__ ===")
class OrderedMeta(type):
@classmethod
def __prepare__(mcs, name, bases):
print(f" __prepare__ called for '{name}' — returning OrderedDict")
return OrderedDict() # body is written into this dict
def __new__(mcs, name, bases, namespace):
print(f" Attributes collected in order: {list(namespace.keys())}")
return super().__new__(mcs, name, bases, namespace)
class Spaceship(metaclass=OrderedMeta):
engines = 4
crew = 7
speed = "warp 9"
print()
# ─────────────────────────────────────────────
# 3. FINAL CLASS via metaclass
# Python has no built-in `final` keyword,
# but a metaclass can raise an error when
# someone tries to subclass a marked class.
# ─────────────────────────────────────────────
print("=== 3. Final class via metaclass ===")
class FinalMeta(type):
_finals = set()
def __new__(mcs, name, bases, namespace):
for base in bases:
if base in FinalMeta._finals:
raise TypeError(f"Cannot subclass '{base.__name__}' — it is final.")
cls = super().__new__(mcs, name, bases, namespace)
if namespace.get("__final__"):
FinalMeta._finals.add(cls)
return cls
class Vault(metaclass=FinalMeta):
__final__ = True
secret = "treasure"
try:
class CrackedVault(Vault): # should explode
pass
except TypeError as e:
print(f" Caught expected error: {e}")
print()
# ─────────────────────────────────────────────
# 4. ABC — Abstract Base Class
# Defines what subclasses *must* implement.
# Cannot be instantiated directly.
# ─────────────────────────────────────────────
print("=== 4. ABC ===")
class Animal(ABC):
@abstractmethod
def make_sound(self):
"""Every animal must implement this."""
...
def sleep(self): # concrete method — shared by all
print(" Zzz...")
class Cat(Animal):
def make_sound(self):
print(" Meow!")
class Dog(Animal):
def make_sound(self):
print(" Woof!")
# Animal() ← would raise TypeError
for animal in [Cat(), Dog()]:
animal.make_sound()
animal.sleep()
print()
# ─────────────────────────────────────────────
# 5. __call__ — making a class instance callable
# Adding __call__ turns an *instance* into
# something you can call like a function.
# ─────────────────────────────────────────────
print("=== 5. __call__ — callable instances ===")
class Multiplier:
def __init__(self, factor):
self.factor = factor
def __call__(self, value): # now the instance IS a function
return value * self.factor
double = Multiplier(2)
triple = Multiplier(3)
print(f" double(5) = {double(5)}") # 10
print(f" triple(5) = {triple(5)}") # 15
print()
# ─────────────────────────────────────────────
# 6. CLASS DECORATOR WITH PARAMETERS
# A decorator factory: a function that returns
# a decorator that wraps the class.
# ─────────────────────────────────────────────
print("=== 6. Class decorator with parameters ===")
def tag(label):
"""Attach a label to a class and log instantiation."""
def decorator(cls):
original_init = cls.__init__
def new_init(self, *args, **kwargs):
print(f" [{label}] Creating a {cls.__name__}")
original_init(self, *args, **kwargs)
cls.__init__ = new_init
cls.__tag__ = label
return cls
return decorator
@tag("EXPERIMENTAL")
class Rocket:
def __init__(self, name):
self.name = name
r = Rocket("Falcon 9")
print(f" Rocket tag: {r.__tag__}")
print()
# ─────────────────────────────────────────────
# 7. SINGLETON via metaclass
# Only one instance of the class can ever exist.
# The metaclass intercepts __call__ to enforce it.
# ─────────────────────────────────────────────
print("=== 7. Singleton via metaclass ===")
class SingletonMeta(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in SingletonMeta._instances:
print(f" Creating the one-and-only {cls.__name__} instance")
SingletonMeta._instances[cls] = super().__call__(*args, **kwargs)
else:
print(f" Returning existing {cls.__name__} instance")
return SingletonMeta._instances[cls]
class DatabaseConnection(metaclass=SingletonMeta):
def __init__(self, url):
self.url = url
db1 = DatabaseConnection("postgres://localhost/mydb")
db2 = DatabaseConnection("postgres://localhost/mydb")
print(f" db1 is db2: {db1 is db2}") # True — same object
print(f" URL: {db1.url}")
print()
# ─────────────────────────────────────────────
# SUMMARY
# ─────────────────────────────────────────────
print("=== Summary ===")
print(" type — the built-in metaclass that creates all classes")
print(" __prepare__ — customize the namespace dict before class body runs")
print(" FinalMeta — enforce 'no subclassing' at the metaclass level")
print(" ABC — declare required methods; prevent direct instantiation")
print(" __call__ — make instances callable like functions")
print(" @tag(label) — parameterized class decorator")
print(" SingletonMeta — one instance only, enforced via metaclass __call__")