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__")