You have 10 classes that need JSON serialization. Instead of copying code to each, create a JsonMixin with to_json() method. Any class can mix it in to gain that capability - composition over inheritance.

Basic mixin

A small class that adds one capability.

mixin_basics.py
# Mixin Basics

def main():
    print("=== Mixin Basics ===\n")

    # What is a mixin?
    print("--- What is a Mixin? ---")
    print("A small class that provides specific functionality")
    print("to be 'mixed into' other classes.\n")

    # Simple mixin example
    print("--- Simple Mixin Example ---")

    # Product with RepresentationMixin
    product = 
    print(f"Product info: {product.get_info()}")
    print(f"Repr: {product!r}")

    # Order with RepresentationMixin
    order = Order("ORD-001", 5)
    print(f"Order info: {order.get_info()}")
    print(f"Repr: {order!r}")

    # Mixin adds functionality to different classes
    print("\n--- Same Mixin, Different Classes ---")

    # Cat with VoiceMixin
    cat = 
    print(f"{cat.name}: ", end="")
    cat.speak()
    cat.whisper()

    # Dog with VoiceMixin
    dog = Dog("Buddy")
    print(f"{dog.name}: ", end="")
    dog.speak()
    dog.whisper()

    # Mixin naming convention
    print("\n--- Naming Convention ---")
    print("Mixins typically end with 'Mixin':")
    print("  • LoggingMixin")
    print("  • SerializableMixin")
    print("  • ComparableMixin")
    print("  • RepresentationMixin")

    print("\n=== Key Points ===")
    print("""
    1. Mixins add specific functionality
    2. Usually don't have __init__ (or minimal)
    3. Designed to be combined with other classes
    4. Name ends with 'Mixin' by convention
    5. Focus on ONE responsibility per mixin
    """)


# RepresentationMixin - adds string representations
class RepresentationMixin:
    """Mixin that provides string representation methods."""

    def get_info(self):
        """Return formatted info string."""
        attrs = ", ".join(f"{k}={v!r}" for k, v in self.__dict__.items())
        return f"{self.__class__.__name__}({attrs})"

    def __repr__(self):
        """Return debug representation."""
        return self.get_info()


# VoiceMixin - adds voice capabilities
class VoiceMixin:
    """Mixin that provides voice-related methods."""

    sound = "..."

    def speak(self):
        """Make the sound loudly."""
        print(f"{self.sound}!")

    def whisper(self):
        """Make the sound quietly."""
        print(f"({self.sound.lower()})")


# Classes using RepresentationMixin
class Product(RepresentationMixin):
    """Product class with representation mixin."""

    def __init__(self, name: str, price: float):
        self.name = name
        self.price = price


class Order(RepresentationMixin):
    """Order class with representation mixin."""

    def __init__(self, order_id: str, quantity: int):
        self.order_id = order_id
        self.quantity = quantity


# Classes using VoiceMixin
class Cat(VoiceMixin):
    """Cat class with voice mixin."""

    sound = "Meow"

    def __init__(self, name: str):
        self.name = name


class Dog(VoiceMixin):
    """Dog class with voice mixin."""

    sound = "Woof"

    def __init__(self, name: str):
        self.name = name


if __name__ == "__main__":
    main()
# Mixin Basics

def main():
    print("=== Mixin Basics ===\n")

    # What is a mixin?
    print("--- What is a Mixin? ---")
    print("A small class that provides specific functionality")
    print("to be 'mixed into' other classes.\n")

    # Simple mixin example
    print("--- Simple Mixin Example ---")

    # Product with RepresentationMixin
    product = 
    print(f"Product info: {product.get_info()}")
    print(f"Repr: {product!r}")

    # Order with RepresentationMixin
    order = Order("ORD-001", 5)
    print(f"Order info: {order.get_info()}")
    print(f"Repr: {order!r}")

    # Mixin adds functionality to different classes
    print("\n--- Same Mixin, Different Classes ---")

    # Cat with VoiceMixin
    cat = 
    print(f"{cat.name}: ", end="")
    cat.speak()
    cat.whisper()

    # Dog with VoiceMixin
    dog = Dog("Buddy")
    print(f"{dog.name}: ", end="")
    dog.speak()
    dog.whisper()

    # Mixin naming convention
    print("\n--- Naming Convention ---")
    print("Mixins typically end with 'Mixin':")
    print("  • LoggingMixin")
    print("  • SerializableMixin")
    print("  • ComparableMixin")
    print("  • RepresentationMixin")

    print("\n=== Key Points ===")
    print("""
    1. Mixins add specific functionality
    2. Usually don't have __init__ (or minimal)
    3. Designed to be combined with other classes
    4. Name ends with 'Mixin' by convention
    5. Focus on ONE responsibility per mixin
    """)


# RepresentationMixin - adds string representations
class RepresentationMixin:
    """Mixin that provides string representation methods."""

    def get_info(self):
        """Return formatted info string."""
        attrs = ", ".join(f"{k}={v!r}" for k, v in self.__dict__.items())
        return f"{self.__class__.__name__}({attrs})"

    def __repr__(self):
        """Return debug representation."""
        return self.get_info()


# VoiceMixin - adds voice capabilities
class VoiceMixin:
    """Mixin that provides voice-related methods."""

    sound = "..."

    def speak(self):
        """Make the sound loudly."""
        print(f"{self.sound}!")

    def whisper(self):
        """Make the sound quietly."""
        print(f"({self.sound.lower()})")


# Classes using RepresentationMixin
class Product(RepresentationMixin):
    """Product class with representation mixin."""

    def __init__(self, name: str, price: float):
        self.name = name
        self.price = price


class Order(RepresentationMixin):
    """Order class with representation mixin."""

    def __init__(self, order_id: str, quantity: int):
        self.order_id = order_id
        self.quantity = quantity


# Classes using VoiceMixin
class Cat(VoiceMixin):
    """Cat class with voice mixin."""

    sound = "Meow"

    def __init__(self, name: str):
        self.name = name


class Dog(VoiceMixin):
    """Dog class with voice mixin."""

    sound = "Woof"

    def __init__(self, name: str):
        self.name = name


if __name__ == "__main__":
    main()
# Mixin Basics

def main():
    print("=== Mixin Basics ===\n")

    # What is a mixin?
    print("--- What is a Mixin? ---")
    print("A small class that provides specific functionality")
    print("to be 'mixed into' other classes.\n")

    # Simple mixin example
    print("--- Simple Mixin Example ---")

    # Product with RepresentationMixin
    product = 
    print(f"Product info: {product.get_info()}")
    print(f"Repr: {product!r}")

    # Order with RepresentationMixin
    order = Order("ORD-001", 5)
    print(f"Order info: {order.get_info()}")
    print(f"Repr: {order!r}")

    # Mixin adds functionality to different classes
    print("\n--- Same Mixin, Different Classes ---")

    # Cat with VoiceMixin
    cat = 
    print(f"{cat.name}: ", end="")
    cat.speak()
    cat.whisper()

    # Dog with VoiceMixin
    dog = Dog("Buddy")
    print(f"{dog.name}: ", end="")
    dog.speak()
    dog.whisper()

    # Mixin naming convention
    print("\n--- Naming Convention ---")
    print("Mixins typically end with 'Mixin':")
    print("  • LoggingMixin")
    print("  • SerializableMixin")
    print("  • ComparableMixin")
    print("  • RepresentationMixin")

    print("\n=== Key Points ===")
    print("""
    1. Mixins add specific functionality
    2. Usually don't have __init__ (or minimal)
    3. Designed to be combined with other classes
    4. Name ends with 'Mixin' by convention
    5. Focus on ONE responsibility per mixin
    """)


# RepresentationMixin - adds string representations
class RepresentationMixin:
    """Mixin that provides string representation methods."""

    def get_info(self):
        """Return formatted info string."""
        attrs = ", ".join(f"{k}={v!r}" for k, v in self.__dict__.items())
        return f"{self.__class__.__name__}({attrs})"

    def __repr__(self):
        """Return debug representation."""
        return self.get_info()


# VoiceMixin - adds voice capabilities
class VoiceMixin:
    """Mixin that provides voice-related methods."""

    sound = "..."

    def speak(self):
        """Make the sound loudly."""
        print(f"{self.sound}!")

    def whisper(self):
        """Make the sound quietly."""
        print(f"({self.sound.lower()})")


# Classes using RepresentationMixin
class Product(RepresentationMixin):
    """Product class with representation mixin."""

    def __init__(self, name: str, price: float):
        self.name = name
        self.price = price


class Order(RepresentationMixin):
    """Order class with representation mixin."""

    def __init__(self, order_id: str, quantity: int):
        self.order_id = order_id
        self.quantity = quantity


# Classes using VoiceMixin
class Cat(VoiceMixin):
    """Cat class with voice mixin."""

    sound = "Meow"

    def __init__(self, name: str):
        self.name = name


class Dog(VoiceMixin):
    """Dog class with voice mixin."""

    sound = "Woof"

    def __init__(self, name: str):
        self.name = name


if __name__ == "__main__":
    main()
# Mixin Basics

def main():
    print("=== Mixin Basics ===\n")

    # What is a mixin?
    print("--- What is a Mixin? ---")
    print("A small class that provides specific functionality")
    print("to be 'mixed into' other classes.\n")

    # Simple mixin example
    print("--- Simple Mixin Example ---")

    # Product with RepresentationMixin
    product = 
    print(f"Product info: {product.get_info()}")
    print(f"Repr: {product!r}")

    # Order with RepresentationMixin
    order = Order("ORD-001", 5)
    print(f"Order info: {order.get_info()}")
    print(f"Repr: {order!r}")

    # Mixin adds functionality to different classes
    print("\n--- Same Mixin, Different Classes ---")

    # Cat with VoiceMixin
    cat = 
    print(f"{cat.name}: ", end="")
    cat.speak()
    cat.whisper()

    # Dog with VoiceMixin
    dog = Dog("Buddy")
    print(f"{dog.name}: ", end="")
    dog.speak()
    dog.whisper()

    # Mixin naming convention
    print("\n--- Naming Convention ---")
    print("Mixins typically end with 'Mixin':")
    print("  • LoggingMixin")
    print("  • SerializableMixin")
    print("  • ComparableMixin")
    print("  • RepresentationMixin")

    print("\n=== Key Points ===")
    print("""
    1. Mixins add specific functionality
    2. Usually don't have __init__ (or minimal)
    3. Designed to be combined with other classes
    4. Name ends with 'Mixin' by convention
    5. Focus on ONE responsibility per mixin
    """)


# RepresentationMixin - adds string representations
class RepresentationMixin:
    """Mixin that provides string representation methods."""

    def get_info(self):
        """Return formatted info string."""
        attrs = ", ".join(f"{k}={v!r}" for k, v in self.__dict__.items())
        return f"{self.__class__.__name__}({attrs})"

    def __repr__(self):
        """Return debug representation."""
        return self.get_info()


# VoiceMixin - adds voice capabilities
class VoiceMixin:
    """Mixin that provides voice-related methods."""

    sound = "..."

    def speak(self):
        """Make the sound loudly."""
        print(f"{self.sound}!")

    def whisper(self):
        """Make the sound quietly."""
        print(f"({self.sound.lower()})")


# Classes using RepresentationMixin
class Product(RepresentationMixin):
    """Product class with representation mixin."""

    def __init__(self, name: str, price: float):
        self.name = name
        self.price = price


class Order(RepresentationMixin):
    """Order class with representation mixin."""

    def __init__(self, order_id: str, quantity: int):
        self.order_id = order_id
        self.quantity = quantity


# Classes using VoiceMixin
class Cat(VoiceMixin):
    """Cat class with voice mixin."""

    sound = "Meow"

    def __init__(self, name: str):
        self.name = name


class Dog(VoiceMixin):
    """Dog class with voice mixin."""

    sound = "Woof"

    def __init__(self, name: str):
        self.name = name


if __name__ == "__main__":
    main()
# Mixin Basics

def main():
    print("=== Mixin Basics ===\n")

    # What is a mixin?
    print("--- What is a Mixin? ---")
    print("A small class that provides specific functionality")
    print("to be 'mixed into' other classes.\n")

    # Simple mixin example
    print("--- Simple Mixin Example ---")

    # Product with RepresentationMixin
    product = 
    print(f"Product info: {product.get_info()}")
    print(f"Repr: {product!r}")

    # Order with RepresentationMixin
    order = Order("ORD-001", 5)
    print(f"Order info: {order.get_info()}")
    print(f"Repr: {order!r}")

    # Mixin adds functionality to different classes
    print("\n--- Same Mixin, Different Classes ---")

    # Cat with VoiceMixin
    cat = 
    print(f"{cat.name}: ", end="")
    cat.speak()
    cat.whisper()

    # Dog with VoiceMixin
    dog = Dog("Buddy")
    print(f"{dog.name}: ", end="")
    dog.speak()
    dog.whisper()

    # Mixin naming convention
    print("\n--- Naming Convention ---")
    print("Mixins typically end with 'Mixin':")
    print("  • LoggingMixin")
    print("  • SerializableMixin")
    print("  • ComparableMixin")
    print("  • RepresentationMixin")

    print("\n=== Key Points ===")
    print("""
    1. Mixins add specific functionality
    2. Usually don't have __init__ (or minimal)
    3. Designed to be combined with other classes
    4. Name ends with 'Mixin' by convention
    5. Focus on ONE responsibility per mixin
    """)


# RepresentationMixin - adds string representations
class RepresentationMixin:
    """Mixin that provides string representation methods."""

    def get_info(self):
        """Return formatted info string."""
        attrs = ", ".join(f"{k}={v!r}" for k, v in self.__dict__.items())
        return f"{self.__class__.__name__}({attrs})"

    def __repr__(self):
        """Return debug representation."""
        return self.get_info()


# VoiceMixin - adds voice capabilities
class VoiceMixin:
    """Mixin that provides voice-related methods."""

    sound = "..."

    def speak(self):
        """Make the sound loudly."""
        print(f"{self.sound}!")

    def whisper(self):
        """Make the sound quietly."""
        print(f"({self.sound.lower()})")


# Classes using RepresentationMixin
class Product(RepresentationMixin):
    """Product class with representation mixin."""

    def __init__(self, name: str, price: float):
        self.name = name
        self.price = price


class Order(RepresentationMixin):
    """Order class with representation mixin."""

    def __init__(self, order_id: str, quantity: int):
        self.order_id = order_id
        self.quantity = quantity


# Classes using VoiceMixin
class Cat(VoiceMixin):
    """Cat class with voice mixin."""

    sound = "Meow"

    def __init__(self, name: str):
        self.name = name


class Dog(VoiceMixin):
    """Dog class with voice mixin."""

    sound = "Woof"

    def __init__(self, name: str):
        self.name = name


if __name__ == "__main__":
    main()
# Mixin Basics

def main():
    print("=== Mixin Basics ===\n")

    # What is a mixin?
    print("--- What is a Mixin? ---")
    print("A small class that provides specific functionality")
    print("to be 'mixed into' other classes.\n")

    # Simple mixin example
    print("--- Simple Mixin Example ---")

    # Product with RepresentationMixin
    product = 
    print(f"Product info: {product.get_info()}")
    print(f"Repr: {product!r}")

    # Order with RepresentationMixin
    order = Order("ORD-001", 5)
    print(f"Order info: {order.get_info()}")
    print(f"Repr: {order!r}")

    # Mixin adds functionality to different classes
    print("\n--- Same Mixin, Different Classes ---")

    # Cat with VoiceMixin
    cat = 
    print(f"{cat.name}: ", end="")
    cat.speak()
    cat.whisper()

    # Dog with VoiceMixin
    dog = Dog("Buddy")
    print(f"{dog.name}: ", end="")
    dog.speak()
    dog.whisper()

    # Mixin naming convention
    print("\n--- Naming Convention ---")
    print("Mixins typically end with 'Mixin':")
    print("  • LoggingMixin")
    print("  • SerializableMixin")
    print("  • ComparableMixin")
    print("  • RepresentationMixin")

    print("\n=== Key Points ===")
    print("""
    1. Mixins add specific functionality
    2. Usually don't have __init__ (or minimal)
    3. Designed to be combined with other classes
    4. Name ends with 'Mixin' by convention
    5. Focus on ONE responsibility per mixin
    """)


# RepresentationMixin - adds string representations
class RepresentationMixin:
    """Mixin that provides string representation methods."""

    def get_info(self):
        """Return formatted info string."""
        attrs = ", ".join(f"{k}={v!r}" for k, v in self.__dict__.items())
        return f"{self.__class__.__name__}({attrs})"

    def __repr__(self):
        """Return debug representation."""
        return self.get_info()


# VoiceMixin - adds voice capabilities
class VoiceMixin:
    """Mixin that provides voice-related methods."""

    sound = "..."

    def speak(self):
        """Make the sound loudly."""
        print(f"{self.sound}!")

    def whisper(self):
        """Make the sound quietly."""
        print(f"({self.sound.lower()})")


# Classes using RepresentationMixin
class Product(RepresentationMixin):
    """Product class with representation mixin."""

    def __init__(self, name: str, price: float):
        self.name = name
        self.price = price


class Order(RepresentationMixin):
    """Order class with representation mixin."""

    def __init__(self, order_id: str, quantity: int):
        self.order_id = order_id
        self.quantity = quantity


# Classes using VoiceMixin
class Cat(VoiceMixin):
    """Cat class with voice mixin."""

    sound = "Meow"

    def __init__(self, name: str):
        self.name = name


class Dog(VoiceMixin):
    """Dog class with voice mixin."""

    sound = "Woof"

    def __init__(self, name: str):
        self.name = name


if __name__ == "__main__":
    main()
# Mixin Basics

def main():
    print("=== Mixin Basics ===\n")

    # What is a mixin?
    print("--- What is a Mixin? ---")
    print("A small class that provides specific functionality")
    print("to be 'mixed into' other classes.\n")

    # Simple mixin example
    print("--- Simple Mixin Example ---")

    # Product with RepresentationMixin
    product = 
    print(f"Product info: {product.get_info()}")
    print(f"Repr: {product!r}")

    # Order with RepresentationMixin
    order = Order("ORD-001", 5)
    print(f"Order info: {order.get_info()}")
    print(f"Repr: {order!r}")

    # Mixin adds functionality to different classes
    print("\n--- Same Mixin, Different Classes ---")

    # Cat with VoiceMixin
    cat = 
    print(f"{cat.name}: ", end="")
    cat.speak()
    cat.whisper()

    # Dog with VoiceMixin
    dog = Dog("Buddy")
    print(f"{dog.name}: ", end="")
    dog.speak()
    dog.whisper()

    # Mixin naming convention
    print("\n--- Naming Convention ---")
    print("Mixins typically end with 'Mixin':")
    print("  • LoggingMixin")
    print("  • SerializableMixin")
    print("  • ComparableMixin")
    print("  • RepresentationMixin")

    print("\n=== Key Points ===")
    print("""
    1. Mixins add specific functionality
    2. Usually don't have __init__ (or minimal)
    3. Designed to be combined with other classes
    4. Name ends with 'Mixin' by convention
    5. Focus on ONE responsibility per mixin
    """)


# RepresentationMixin - adds string representations
class RepresentationMixin:
    """Mixin that provides string representation methods."""

    def get_info(self):
        """Return formatted info string."""
        attrs = ", ".join(f"{k}={v!r}" for k, v in self.__dict__.items())
        return f"{self.__class__.__name__}({attrs})"

    def __repr__(self):
        """Return debug representation."""
        return self.get_info()


# VoiceMixin - adds voice capabilities
class VoiceMixin:
    """Mixin that provides voice-related methods."""

    sound = "..."

    def speak(self):
        """Make the sound loudly."""
        print(f"{self.sound}!")

    def whisper(self):
        """Make the sound quietly."""
        print(f"({self.sound.lower()})")


# Classes using RepresentationMixin
class Product(RepresentationMixin):
    """Product class with representation mixin."""

    def __init__(self, name: str, price: float):
        self.name = name
        self.price = price


class Order(RepresentationMixin):
    """Order class with representation mixin."""

    def __init__(self, order_id: str, quantity: int):
        self.order_id = order_id
        self.quantity = quantity


# Classes using VoiceMixin
class Cat(VoiceMixin):
    """Cat class with voice mixin."""

    sound = "Meow"

    def __init__(self, name: str):
        self.name = name


class Dog(VoiceMixin):
    """Dog class with voice mixin."""

    sound = "Woof"

    def __init__(self, name: str):
        self.name = name


if __name__ == "__main__":
    main()
# Mixin Basics

def main():
    print("=== Mixin Basics ===\n")

    # What is a mixin?
    print("--- What is a Mixin? ---")
    print("A small class that provides specific functionality")
    print("to be 'mixed into' other classes.\n")

    # Simple mixin example
    print("--- Simple Mixin Example ---")

    # Product with RepresentationMixin
    product = 
    print(f"Product info: {product.get_info()}")
    print(f"Repr: {product!r}")

    # Order with RepresentationMixin
    order = Order("ORD-001", 5)
    print(f"Order info: {order.get_info()}")
    print(f"Repr: {order!r}")

    # Mixin adds functionality to different classes
    print("\n--- Same Mixin, Different Classes ---")

    # Cat with VoiceMixin
    cat = 
    print(f"{cat.name}: ", end="")
    cat.speak()
    cat.whisper()

    # Dog with VoiceMixin
    dog = Dog("Buddy")
    print(f"{dog.name}: ", end="")
    dog.speak()
    dog.whisper()

    # Mixin naming convention
    print("\n--- Naming Convention ---")
    print("Mixins typically end with 'Mixin':")
    print("  • LoggingMixin")
    print("  • SerializableMixin")
    print("  • ComparableMixin")
    print("  • RepresentationMixin")

    print("\n=== Key Points ===")
    print("""
    1. Mixins add specific functionality
    2. Usually don't have __init__ (or minimal)
    3. Designed to be combined with other classes
    4. Name ends with 'Mixin' by convention
    5. Focus on ONE responsibility per mixin
    """)


# RepresentationMixin - adds string representations
class RepresentationMixin:
    """Mixin that provides string representation methods."""

    def get_info(self):
        """Return formatted info string."""
        attrs = ", ".join(f"{k}={v!r}" for k, v in self.__dict__.items())
        return f"{self.__class__.__name__}({attrs})"

    def __repr__(self):
        """Return debug representation."""
        return self.get_info()


# VoiceMixin - adds voice capabilities
class VoiceMixin:
    """Mixin that provides voice-related methods."""

    sound = "..."

    def speak(self):
        """Make the sound loudly."""
        print(f"{self.sound}!")

    def whisper(self):
        """Make the sound quietly."""
        print(f"({self.sound.lower()})")


# Classes using RepresentationMixin
class Product(RepresentationMixin):
    """Product class with representation mixin."""

    def __init__(self, name: str, price: float):
        self.name = name
        self.price = price


class Order(RepresentationMixin):
    """Order class with representation mixin."""

    def __init__(self, order_id: str, quantity: int):
        self.order_id = order_id
        self.quantity = quantity


# Classes using VoiceMixin
class Cat(VoiceMixin):
    """Cat class with voice mixin."""

    sound = "Meow"

    def __init__(self, name: str):
        self.name = name


class Dog(VoiceMixin):
    """Dog class with voice mixin."""

    sound = "Woof"

    def __init__(self, name: str):
        self.name = name


if __name__ == "__main__":
    main()
# Mixin Basics

def main():
    print("=== Mixin Basics ===\n")

    # What is a mixin?
    print("--- What is a Mixin? ---")
    print("A small class that provides specific functionality")
    print("to be 'mixed into' other classes.\n")

    # Simple mixin example
    print("--- Simple Mixin Example ---")

    # Product with RepresentationMixin
    product = 
    print(f"Product info: {product.get_info()}")
    print(f"Repr: {product!r}")

    # Order with RepresentationMixin
    order = Order("ORD-001", 5)
    print(f"Order info: {order.get_info()}")
    print(f"Repr: {order!r}")

    # Mixin adds functionality to different classes
    print("\n--- Same Mixin, Different Classes ---")

    # Cat with VoiceMixin
    cat = 
    print(f"{cat.name}: ", end="")
    cat.speak()
    cat.whisper()

    # Dog with VoiceMixin
    dog = Dog("Buddy")
    print(f"{dog.name}: ", end="")
    dog.speak()
    dog.whisper()

    # Mixin naming convention
    print("\n--- Naming Convention ---")
    print("Mixins typically end with 'Mixin':")
    print("  • LoggingMixin")
    print("  • SerializableMixin")
    print("  • ComparableMixin")
    print("  • RepresentationMixin")

    print("\n=== Key Points ===")
    print("""
    1. Mixins add specific functionality
    2. Usually don't have __init__ (or minimal)
    3. Designed to be combined with other classes
    4. Name ends with 'Mixin' by convention
    5. Focus on ONE responsibility per mixin
    """)


# RepresentationMixin - adds string representations
class RepresentationMixin:
    """Mixin that provides string representation methods."""

    def get_info(self):
        """Return formatted info string."""
        attrs = ", ".join(f"{k}={v!r}" for k, v in self.__dict__.items())
        return f"{self.__class__.__name__}({attrs})"

    def __repr__(self):
        """Return debug representation."""
        return self.get_info()


# VoiceMixin - adds voice capabilities
class VoiceMixin:
    """Mixin that provides voice-related methods."""

    sound = "..."

    def speak(self):
        """Make the sound loudly."""
        print(f"{self.sound}!")

    def whisper(self):
        """Make the sound quietly."""
        print(f"({self.sound.lower()})")


# Classes using RepresentationMixin
class Product(RepresentationMixin):
    """Product class with representation mixin."""

    def __init__(self, name: str, price: float):
        self.name = name
        self.price = price


class Order(RepresentationMixin):
    """Order class with representation mixin."""

    def __init__(self, order_id: str, quantity: int):
        self.order_id = order_id
        self.quantity = quantity


# Classes using VoiceMixin
class Cat(VoiceMixin):
    """Cat class with voice mixin."""

    sound = "Meow"

    def __init__(self, name: str):
        self.name = name


class Dog(VoiceMixin):
    """Dog class with voice mixin."""

    sound = "Woof"

    def __init__(self, name: str):
        self.name = name


if __name__ == "__main__":
    main()

Mixins add single behavior. Usually no __init__, just methods.

mixin Small class adding specific functionality. Mixed into other classes.

Composing mixins

Combine multiple mixins for multiple capabilities.

composing_mixins.py
# Composing Multiple Mixins

from datetime import datetime

def main():
    print("=== Composing Multiple Mixins ===\n")

    # Multiple mixins in one class
    print("--- Multiple Mixins Combined ---")

    # DataRecord with multiple mixins
    record = DataRecord(1, "Sample data", "active")

    print("DataRecord capabilities:")
    print(f"  As dict: {record.to_dict()}")
    print(f"  Timestamp: {record.created_at}")
    record.log("Record created")

    # Compare with DataRecord without mixins
    print("\n--- Without Mixins vs With Mixins ---")

    simple = SimpleRecord(1, "Simple")
    print(f"SimpleRecord: {simple}")

    enhanced = EnhancedRecord(1, "Enhanced")
    print(f"EnhancedRecord: {enhanced}")
    print(f"  as_json: {enhanced.as_json()}")
    print(f"  created_at: {enhanced.created_at}")

    # Mixin order matters
    print("\n--- Mixin Order (MRO) ---")

    print("class DataRecord(DictMixin, TimestampMixin, LoggingMixin):")
    print(f"MRO: {[c.__name__ for c in DataRecord.__mro__]}")

    # User with all mixins
    print("\n--- User with Multiple Mixins ---")

    user = User(42, "alice", "alice@example.com")
    print(f"User dict: {user.to_dict()}")
    print(f"Has timestamp: {hasattr(user, 'created_at')}")
    user.log("User loaded from database")

    # Selective mixin usage
    print("\n--- Selective Mixin Usage ---")

    # LogOnly class only has logging
    logger = LogOnly("Logger instance")
    logger.log("Testing selective mixin")
    print(f"Has to_dict? {hasattr(logger, 'to_dict')}")
    print(f"Has created_at? {hasattr(logger, 'created_at')}")

    print("\n=== Key Points ===")
    print("""
    1. Combine multiple mixins for rich functionality
    2. Each mixin adds specific capability
    3. Order in inheritance affects MRO
    4. Pick only the mixins you need
    5. Mixins should be independent (no mixin depends on another)
    """)


# Define individual mixins

class DictMixin:
    """Mixin for dictionary conversion."""

    def to_dict(self) -> dict:
        """Convert object to dictionary."""
        return {k: v for k, v in self.__dict__.items()
                if not k.startswith('_')}

    def as_json(self) -> str:
        """Return JSON-like string representation."""
        import json
        return json.dumps(self.to_dict(), default=str)


class TimestampMixin:
    """Mixin for automatic timestamps."""

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.created_at = datetime.now()


class LoggingMixin:
    """Mixin for logging capability."""

    def log(self, message: str):
        """Log a message with class name prefix."""
        print(f"[{self.__class__.__name__}] {message}")


# Class combining multiple mixins
class DataRecord(DictMixin, TimestampMixin, LoggingMixin):
    """Data record with dict, timestamp, and logging capabilities."""

    def __init__(self, record_id: int, data: str, status: str):
        super().__init__()
        self.record_id = record_id
        self.data = data
        self.status = status


# Comparison: without vs with mixins

class SimpleRecord:
    """Record without any mixins."""

    def __init__(self, record_id: int, data: str):
        self.record_id = record_id
        self.data = data

    def __str__(self):
        return f"SimpleRecord({self.record_id}, {self.data})"


class EnhancedRecord(DictMixin, TimestampMixin):
    """Record with dict and timestamp mixins."""

    def __init__(self, record_id: int, data: str):
        super().__init__()
        self.record_id = record_id
        self.data = data

    def __str__(self):
        return f"EnhancedRecord({self.record_id}, {self.data})"


# User class with all mixins
class User(DictMixin, TimestampMixin, LoggingMixin):
    """User with full mixin support."""

    def __init__(self, user_id: int, username: str, email: str):
        super().__init__()
        self.user_id = user_id
        self.username = username
        self.email = email


# Selective mixin usage
class LogOnly(LoggingMixin):
    """Class with only logging mixin."""

    def __init__(self, name: str):
        self.name = name


if __name__ == "__main__":
    main()

class MyClass(MixinA, MixinB, Base): - gets all mixin methods.

Mixin with super()

Cooperative mixins that chain properly.

mixin_with_super.py
# Using super() in Mixins

def main():
    print("=== Using super() in Mixins ===\n")

    # Why super() in mixins?
    print("--- Why super() in Mixins? ---")
    print("When mixins need to participate in __init__ chain,")
    print("super() ensures all __init__ methods are called.\n")

    # Without super() - broken chain
    print("--- Without super() (Broken) ---")

    try:
        broken = BrokenExample("test")
        print(f"value: {broken.value}")
        print(f"initialized: {getattr(broken, 'initialized', 'MISSING')}")
        print(f"timestamped: {getattr(broken, 'timestamped', 'MISSING')}")
    except AttributeError as e:
        print(f"Error: {e}")

    # With super() - proper chain
    print("\n--- With super() (Correct) ---")

    correct = CorrectExample("test")
    print(f"value: {correct.value}")
    print(f"initialized: {correct.initialized}")
    print(f"timestamped: {correct.timestamped}")

    # The **kwargs pattern
    print("\n--- The **kwargs Pattern ---")
    print("Pass extra kwargs through super() to next class:")
    print("""
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.my_attr = ...
    """)

    # Full cooperative example
    print("--- Full Cooperative Example ---")

    entity = TrackedEntity(name="Widget", category="product")
    print(f"Entity: name={entity.name}, category={entity.category}")
    print(f"  has_id: {entity.entity_id[:8]}...")
    print(f"  created_at: {entity.created_at}")
    print(f"  initialized: {entity.initialized}")

    # MRO walkthrough
    print("\n--- MRO Walkthrough ---")
    print(f"TrackedEntity MRO: {[c.__name__ for c in TrackedEntity.__mro__]}")
    print("""
    Call order:
    1. TrackedEntity.__init__(name="Widget", category="product")
    2. → IdMixin.__init__(category="product") [name consumed]
    3. → TimestampMixin.__init__() [category consumed]
    4. → InitMixin.__init__()
    5. → object.__init__()
    """)

    print("\n=== Key Points ===")
    print("""
    1. Always use super().__init__(**kwargs) in mixins
    2. Consume your parameters, pass the rest via **kwargs
    3. All __init__ methods get called in MRO order
    4. Last mixin in chain should call super() too
    5. This pattern enables true cooperative inheritance
    """)


# Broken: Mixins without proper super()

class BrokenMixinA:
    """Mixin that DOESN'T use super()."""

    def __init__(self):
        self.initialized = True
        # No super() call! Chain breaks here.


class BrokenMixinB:
    """Another mixin that DOESN'T use super()."""

    def __init__(self):
        self.timestamped = True
        # No super() call!


class BrokenExample(BrokenMixinA, BrokenMixinB):
    """BrokenMixinB.__init__ never called!"""

    def __init__(self, value):
        super().__init__()
        self.value = value


# Correct: Mixins with proper super()

class CorrectMixinA:
    """Mixin that properly uses super()."""

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.initialized = True


class CorrectMixinB:
    """Another mixin that properly uses super()."""

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.timestamped = True


class CorrectExample(CorrectMixinA, CorrectMixinB):
    """Both mixin __init__ methods get called!"""

    def __init__(self, value, **kwargs):
        super().__init__(**kwargs)
        self.value = value


# Full cooperative inheritance example

import uuid
from datetime import datetime

class InitMixin:
    """Base mixin - ends the super() chain."""

    def __init__(self, **kwargs):
        super().__init__()
        self.initialized = True


class TimestampMixin:
    """Adds creation timestamp."""

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.created_at = datetime.now().isoformat()


class IdMixin:
    """Adds unique ID."""

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.entity_id = str(uuid.uuid4())


class TrackedEntity(IdMixin, TimestampMixin, InitMixin):
    """Entity with ID, timestamp, and init tracking."""

    def __init__(self, name: str, category: str, **kwargs):
        super().__init__(**kwargs)
        self.name = name
        self.category = category


if __name__ == "__main__":
    main()

super() ensures all mixins in chain get called.

Common mixin patterns

Serialization, comparison, logging mixins.

common_mixins.py
# Common Mixin Patterns

import json
from datetime import datetime

def main():
    print("=== Common Mixin Patterns ===\n")

    # 1. Serialization Mixin
    print("--- 1. Serialization Mixin ---")

    user = User(1, "alice", "alice@example.com")
    print(f"Original: {user}")
    print(f"to_dict: {user.to_dict()}")
    print(f"to_json: {user.to_json()}")

    # Reconstruct from dict
    data = user.to_dict()
    user2 = User.from_dict(data)
    print(f"Reconstructed: {user2}")

    # 2. Comparison Mixin
    print("\n--- 2. Comparison Mixin ---")

    v1 = Version(1, 0, 0)
    v2 = Version(1, 2, 0)
    v3 = Version(1, 0, 0)

    print(f"v1 = {v1}")
    print(f"v2 = {v2}")
    print(f"v3 = {v3}")

    print(f"v1 == v3: {v1 == v3}")
    print(f"v1 < v2: {v1 < v2}")
    print(f"v2 > v1: {v2 > v1}")
    print(f"v1 <= v3: {v1 <= v3}")

    # Sorting works too
    versions = [v2, v1, v3]
    print(f"Sorted: {sorted(versions)}")

    # 3. Validation Mixin
    print("\n--- 3. Validation Mixin ---")

    product = Product("Laptop", 999.99, 10)
    print(f"Valid product: {product}")

    try:
        invalid = Product("", -100, -5)
    except ValueError as e:
        print(f"Validation failed: {e}")

    # 4. Repr Mixin
    print("\n--- 4. Repr Mixin ---")

    item = Item("Widget", 42)
    print(f"repr: {item!r}")
    print(f"str: {item}")

    print("\n=== Common Mixin Use Cases ===")
    print("""
    • SerializableMixin: Convert to/from dict, JSON, XML
    • ComparableMixin: Enable <, >, ==, <=, >= operators
    • ValidatableMixin: Add validation methods
    • ReprMixin: Auto-generate __repr__ and __str__
    • HashableMixin: Make objects hashable (for sets/dicts)
    • CopyableMixin: Deep/shallow copy support
    """)


# 1. Serialization Mixin
class SerializableMixin:
    """Mixin for JSON serialization/deserialization."""

    def to_dict(self) -> dict:
        """Convert to dictionary."""
        return {k: v for k, v in self.__dict__.items()
                if not k.startswith('_')}

    def to_json(self) -> str:
        """Convert to JSON string."""
        return json.dumps(self.to_dict(), default=str)

    @classmethod
    def from_dict(cls, data: dict):
        """Create instance from dictionary."""
        return cls(**data)


# 2. Comparison Mixin
class ComparableMixin:
    """Mixin that enables comparison operators.

    Requires: _compare_key() method in the class.
    """

    def _compare_key(self):
        """Override this to define comparison key."""
        raise NotImplementedError("Subclass must implement _compare_key()")

    def __eq__(self, other):
        if not isinstance(other, self.__class__):
            return NotImplemented
        return self._compare_key() == other._compare_key()

    def __lt__(self, other):
        if not isinstance(other, self.__class__):
            return NotImplemented
        return self._compare_key() < other._compare_key()

    def __le__(self, other):
        return self == other or self < other

    def __gt__(self, other):
        if not isinstance(other, self.__class__):
            return NotImplemented
        return self._compare_key() > other._compare_key()

    def __ge__(self, other):
        return self == other or self > other


# 3. Validation Mixin
class ValidatableMixin:
    """Mixin that adds validation support."""

    def validate(self):
        """Validate the object. Override _get_validations()."""
        errors = []
        for field, value, check, message in self._get_validations():
            if not check(value):
                errors.append(f"{field}: {message}")

        if errors:
            raise ValueError("; ".join(errors))

    def _get_validations(self):
        """Return list of (field, value, check_func, error_msg)."""
        return []


# 4. Repr Mixin
class ReprMixin:
    """Mixin that auto-generates __repr__ and __str__."""

    def __repr__(self):
        attrs = ", ".join(f"{k}={v!r}" for k, v in self.__dict__.items()
                         if not k.startswith('_'))
        return f"{self.__class__.__name__}({attrs})"

    def __str__(self):
        return self.__repr__()


# Classes using the mixins

class User(SerializableMixin):
    """User with serialization support."""

    def __init__(self, user_id: int, username: str, email: str):
        self.user_id = user_id
        self.username = username
        self.email = email

    def __str__(self):
        return f"User({self.user_id}, {self.username})"


class Version(ComparableMixin):
    """Version with comparison support."""

    def __init__(self, major: int, minor: int, patch: int):
        self.major = major
        self.minor = minor
        self.patch = patch

    def _compare_key(self):
        """Comparison key: tuple of (major, minor, patch)."""
        return (self.major, self.minor, self.patch)

    def __repr__(self):
        return f"v{self.major}.{self.minor}.{self.patch}"


class Product(ValidatableMixin):
    """Product with validation support."""

    def __init__(self, name: str, price: float, quantity: int):
        self.name = name
        self.price = price
        self.quantity = quantity
        self.validate()

    def _get_validations(self):
        """Define product validations."""
        return [
            ("name", self.name, lambda x: x and len(x) > 0, "Name is required"),
            ("price", self.price, lambda x: x >= 0, "Price must be non-negative"),
            ("quantity", self.quantity, lambda x: x >= 0, "Quantity must be non-negative"),
        ]

    def __str__(self):
        return f"Product({self.name}, ${self.price}, qty={self.quantity})"


class Item(ReprMixin):
    """Item with auto-generated repr."""

    def __init__(self, name: str, value: int):
        self.name = name
        self.value = value


if __name__ == "__main__":
    main()

Popular patterns: JsonMixin, ComparableMixin, LoggingMixin.

Mixin vs inheritance

When to use each approach.

mixin_vs_inheritance.py
# Mixin vs Regular Inheritance

def main():
    print("=== Mixin vs Regular Inheritance ===\n")

    # When to use regular inheritance
    print("--- When to Use Regular Inheritance ---")
    print("Use when: IS-A relationship exists")
    print("Example: Dog IS-A Animal\n")

    dog = Dog("Buddy")
    print(f"{dog.name} says: ", end="")
    dog.speak()
    dog.move()

    # When to use mixins
    print("\n--- When to Use Mixins ---")
    print("Use when: Adding CAPABILITY (HAS-A behavior)")
    print("Example: Dog HAS logging capability\n")

    logged_dog = LoggedDog("Max")
    logged_dog.log("Dog created")
    logged_dog.speak()

    # Comparison: Same behavior, different approaches
    print("\n--- Comparison: Two Approaches ---")
    print("Goal: Add serialization to multiple unrelated classes\n")

    # Approach 1: Base class (problematic)
    print("Approach 1: Shared Base Class")
    print("  class User(SerializableBase): ...")
    print("  class Product(SerializableBase): ...")
    print("  Problem: What if User already has a base class?")
    print("  Problem: SerializableBase isn't really a 'parent'\n")

    # Approach 2: Mixin (better)
    print("Approach 2: Mixin")
    print("  class User(UserBase, SerializableMixin): ...")
    print("  class Product(ProductBase, SerializableMixin): ...")
    print("  Benefit: Can add to any class hierarchy")
    print("  Benefit: Clear that it's adding capability, not identity\n")

    # Demonstrate with real classes
    print("--- Real Example ---")

    user = User("alice", "alice@example.com")
    product = Product("Laptop", 999.99)

    print(f"User: {user.get_name()}")
    print(f"User serialized: {user.to_dict()}")

    print(f"Product: {product.get_name()}")
    print(f"Product serialized: {product.to_dict()}")

    # Decision guide
    print("\n=== Decision Guide ===")
    print("""
    Use REGULAR INHERITANCE when:
    ┌─────────────────────────────────────────────────┐
    │ • Clear IS-A relationship (Dog IS-A Animal)     │
    │ • Shared state and behavior                     │
    │ • Objects are naturally in same hierarchy       │
    │ • Want to override parent methods               │
    └─────────────────────────────────────────────────┘

    Use MIXIN when:
    ┌─────────────────────────────────────────────────┐
    │ • Adding capability (HAS-A behavior)            │
    │ • Unrelated classes need same feature           │
    │ • Small, focused functionality                  │
    │ • No shared identity/state                      │
    │ • Want to compose behaviors flexibly            │
    └─────────────────────────────────────────────────┘
    """)

    # Anti-patterns
    print("=== Anti-Patterns to Avoid ===")
    print("""
    ✗ Mixin with complex state (use regular class)
    ✗ Mixin that depends on other mixins (order issues)
    ✗ Too many mixins (hard to understand)
    ✗ Using inheritance just for code reuse
    ✗ Deep inheritance hierarchies
    """)


# Regular Inheritance Example

class Animal:
    """Base class - defines what an animal IS."""

    def __init__(self, name: str):
        self.name = name

    def speak(self):
        """Override in subclass."""
        print("Some sound")

    def move(self):
        """Common to all animals."""
        print(f"{self.name} is moving")


class Dog(Animal):
    """Dog IS-A Animal - clear inheritance."""

    def speak(self):
        print("Woof!")


# Mixin Example

class LoggingMixin:
    """Adds logging CAPABILITY."""

    def log(self, message: str):
        print(f"[{self.__class__.__name__}] {message}")


class LoggedDog(Animal, LoggingMixin):
    """Dog with logging capability added."""

    def speak(self):
        self.log("About to bark")
        print("Woof!")


# Comparison: Adding serialization

class SerializableMixin:
    """Mixin - adds serialization CAPABILITY."""

    def to_dict(self) -> dict:
        return {k: v for k, v in self.__dict__.items()
                if not k.startswith('_')}


# Base classes representing different domains

class Entity:
    """Base for database entities."""

    def __init__(self):
        self._id = None

    def get_name(self) -> str:
        raise NotImplementedError


class Item:
    """Base for store items."""

    def __init__(self):
        self._sku = None

    def get_name(self) -> str:
        raise NotImplementedError


# Classes using mixin with their own base classes

class User(Entity, SerializableMixin):
    """User IS-A Entity, HAS serialization."""

    def __init__(self, username: str, email: str):
        super().__init__()
        self.username = username
        self.email = email

    def get_name(self) -> str:
        return self.username


class Product(Item, SerializableMixin):
    """Product IS-A Item, HAS serialization."""

    def __init__(self, name: str, price: float):
        super().__init__()
        self.name = name
        self.price = price

    def get_name(self) -> str:
        return self.name


if __name__ == "__main__":
    main()

Inheritance: "is-a" relationship. Mixin: "has capability". Choose wisely.

Exercise: practical.py

Build a web framework-style mixin system