Courses/Python/Mixins, Multiple Inheritance & OOP Patterns

    Lesson 30 โ€ข Advanced

    Mixins, Multiple Inheritance & OOP Patterns

    Learn the REAL Python OOP system used by Django, FastAPI, SQLAlchemy, Pydantic, PyTorch, and Scrapy. Master mixins, multiple inheritance, and professional OOP patterns used in large-scale frameworks.

    ๐Ÿ”ฅ Mixins, Multiple Inheritance & OOP Patterns

    This lesson teaches the REAL Python OOP system used by:

    FrameworkCommon MixinsPurpose
    DjangoLoginRequiredMixin, PermissionMixinAuthentication & authorization
    SQLAlchemyTimestampMixin, SerializerMixinDatabase models & serialization
    FastAPIModelConfigMixinConfiguration & validation
    ScrapyRetryMixin, LogMixinRobustness & debugging

    This is how large Python frameworks organise reusable behaviour at scale.

    โญ 1. What Are Mixins?

    A mixin is:

    • โœ” a small class
    • โœ” provides one specific behaviour
    • โœ” not meant to be instantiated on its own
    • โœ” used to "mix" extra features into other classes

    Example of a simple mixin:

    Simple Mixin Example

    A mixin that adds a pretty() method to any class

    Try it Yourself ยป
    Python
    class PrintableMixin:
        def pretty(self):
            return f"<{self.__class__.__name__}: {self.__dict__}>"
    
    class User(PrintableMixin):
        def __init__(self, name):
            self.name = name
    
    # Now:
    print(User("Boopie").pretty())

    Mixins = adding reusable abilities, not designing base types.

    โญ 2. Why Mixins Exist

    Large codebases avoid copying logic.

    Instead, they break features into "behaviour modules":

    Examples:

    • โœ” LoggingMixin
    • โœ” PermissionMixin
    • โœ” RateLimitMixin
    • โœ” CacheMixin
    • โœ” TokenAuthMixin
    • โœ” SerializerMixin
    • โœ” RetryMixin
    • โœ” EventEmitterMixin

    Each mixin provides ONE capability.

    Your class can combine many of them:

    Combining Multiple Mixins

    A class that combines multiple mixin behaviours

    Try it Yourself ยป
    Python
    # Example of combining multiple mixins
    class AuthMixin:
        def authenticate(self):
            print("Authenticating...")
    
    class LoggingMixin:
        def log(self, msg):
            print(f"[LOG] {msg}")
    
    class RetryMixin:
        def retry(self, func, attempts=3):
            for i in range(attempts):
                try:
                    return func()
                except Exception as e:
                    print(f"Attempt {i+1} failed: {e}")
    
    class CacheMixin:
        _cache = {}
        def cache_get(self, key):
            return 
    ...

    This avoids the inheritance mess of shoving everything into one giant parent class.

    โญ 3. When NOT To Use Mixins

    Do NOT use mixins for:

    • โŒ complex logic
    • โŒ core business functionality
    • โŒ storage of critical state
    • โŒ large method sets
    • โŒ tightly coupled behaviour

    Use mixins for:

    • โœ” helpers
    • โœ” behaviour
    • โœ” convenience methods
    • โœ” add-on features
    • โœ” small utilities

    โš™๏ธ 4. Multiple Inheritance โ€” How Python Makes This Work

    Python supports full multiple inheritance:

    Multiple Inheritance Basics

    A class inheriting from multiple parent classes

    Try it Yourself ยป
    Python
    class A:
        def greet(self):
            return "Hello from A"
    
    class B:
        def greet(self):
            return "Hello from B"
    
    class C(A, B):
        pass
    
    # C inherits from both A and B
    c = C()
    print(c.greet())  # prints "Hello from A" because A is first

    Behind the scenes, Python uses:

    ๐Ÿ‘‰ MRO (Method Resolution Order)

    This determines which class Python checks first when calling a method.

    โญ 5. How to View the MRO

    Critical for debugging inheritance:

    Viewing the MRO

    Check the Method Resolution Order for debugging

    Try it Yourself ยป
    Python
    class A:
        def speak(self): print("A")
    
    class B:
        def speak(self): print("B")
    
    class C(A, B):
        pass
    
    # View the Method Resolution Order
    print(C.mro())
    # Or use __mro__
    print(C.__mro__)
    
    # Output example:
    # [<class C>, <class A>, <class B>, <class object>]

    This explains:

    • โœ” method lookup
    • โœ” attribute access
    • โœ” super() behaviour
    • โœ” complex inheritance chains
    • โœ” how Python avoids the diamond problem

    ๐Ÿ”ท 6. The Diamond Problem (and Python's solution)

    Diamond inheritance:

        A
       / \
      B   C
       \ /
        D

    All classes inherit from A.

    Without control โ†’ chaos.

    Python solves this using C3 linearization.

    This ensures:

    • โœ” deterministic lookup order
    • โœ” no ambiguity
    • โœ” super() always moves to the next class in the hierarchy

    โญ 7. Why super() Matters in Multiple Inheritance

    Many languages treat super() like:

    โžก๏ธ "call ONLY the parent class"

    Python treats super() as:

    โžก๏ธ "call the NEXT class in the MRO chain"

    This allows cooperative multiple inheritance.

    super() in Multiple Inheritance

    See how super() chains through the MRO

    Try it Yourself ยป
    Python
    class A:
        def process(self):
            print("A")
    
    class B:
        def process(self):
            print("B")
    
    class C:
        def process(self):
            print("C")
    
    class D(A, B, C):
        def process(self):
            print("D")
            super().process()
    
    # Watch the chain work!
    d = D()
    d.process()
    print("\nMRO:", [cls.__name__ for cls in D.mro()])

    That's the power of super() + MRO.

    โšก 8. Designing Cooperative Mixins

    Every mixin you write should:

    • โœ” call super()
    • โœ” accept *args, **kwargs
    • โœ” avoid breaking the chain

    Example:

    Cooperative Mixins

    Mixins that properly chain with super()

    Try it Yourself ยป
    Python
    class LoggingMixin:
        def save(self, *args, **kwargs):
            print("Logging save...")
            return super().save(*args, **kwargs)
    
    class ValidationMixin:
        def save(self, *args, **kwargs):
            print("Validating...")
            return super().save(*args, **kwargs)
    
    class BaseModel:
        def save(self, *args, **kwargs):
            print("Saving to database!")
            return True
    
    class User(LoggingMixin, ValidationMixin, BaseModel):
        pass
    
    user = User()
    user.save()

    If every class cooperates, Python can thread all behaviours together.

    This is how Django CBVs (Class-Based Views) work internally.

    ๐Ÿ”ถ 9. Mixins Should NOT Have __init__

    Mixins generally avoid __init__ because it breaks cooperative inheritance.

    If needed, you MUST write:

    Mixin with __init__

    Proper way to use __init__ in mixins

    Try it Yourself ยป
    Python
    class ConfigMixin:
        def __init__(self, *args, **kwargs):
            self.debug = True
            super().__init__(*args, **kwargs)
    
    class BaseClass:
        def __init__(self, name):
            self.name = name
    
    class MyClass(ConfigMixin, BaseClass):
        pass
    
    obj = MyClass("Test")
    print(f"Name: {obj.name}, Debug: {obj.debug}")

    Otherwise, your mixin may block other parents from initialising.

    โญ 10. Real-World Mixin Examples

    Examples from popular frameworks:

    Real-World Framework Mixins

    Examples from Django, SQLAlchemy, and FastAPI

    Try it Yourself ยป
    Python
    # Django-style mixins
    class LoginRequiredMixin:
        """Requires user to be logged in"""
        def dispatch(self, request, *args, **kwargs):
            if not request.user.is_authenticated:
                return "Redirect to login"
            return super().dispatch(request, *args, **kwargs)
    
    class PermissionRequiredMixin:
        """Requires specific permissions"""
        permission_required = None
        
        def has_permission(self):
            return self.permission_required is not None
    
    # SQLAlchemy-style mixin
    cla
    ...

    Mixins dominate real frameworks.

    ๐Ÿง  11. Interface Mixins (Behaviour Contracts)

    You can define behaviour expectations:

    Interface Mixins

    Defining behaviour contracts with mixins

    Try it Yourself ยป
    Python
    class JSONSerializableMixin:
        def to_json(self):
            raise NotImplementedError("Subclass must implement to_json()")
    
    class XMLSerializableMixin:
        def to_xml(self):
            raise NotImplementedError("Subclass must implement to_xml()")
    
    class User(JSONSerializableMixin):
        def __init__(self, name, age):
            self.name = name
            self.age = age
        
        def to_json(self):
            return f'{{"name": "{self.name}", "age": {self.age}}}'
    
    user = User("Boopie", 16)
    print(user.to_json(
    ...

    Used when:

    • โœ” you need consistency
    • โœ” library expects a method to exist
    • โœ” plugin systems

    ๐Ÿ”ฅ 12. Multiple Inheritance for Role Composition

    Rather than long inheritance like:

    AdminUser โ†’ User โ†’ BaseUser โ†’ Object

    You use role stacking:

    Role Composition

    Composing roles using multiple inheritance

    Try it Yourself ยป
    Python
    class AuthMixin:
        def authenticate(self):
            return True
    
    class PermissionMixin:
        permissions = []
        def has_permission(self, perm):
            return perm in self.permissions
    
    class LoggingMixin:
        def log_action(self, action):
            print(f"[LOG] {action}")
    
    class BaseUser:
        def __init__(self, name):
            self.name = name
    
    class AdminUser(AuthMixin, PermissionMixin, LoggingMixin, BaseUser):
        permissions = ["read", "write", "delete", "admin"]
    
    admin = AdminUser("SuperAdmi
    ...

    Roles = flexibility.

    This is scalable for 10+ behaviour components.

    ๐Ÿงฉ 13. Composition vs Inheritance (Critical Design Decision)

    โœ” Use inheritance when:

    • โ€ข "is a" relationship
    • โ€ข class hierarchy makes sense
    • โ€ข polymorphic behaviour

    โœ” Use composition when:

    • โ€ข "has a" relationship
    • โ€ข behaviour shouldn't leak
    • โ€ข state belongs to specific objects

    Example:

    โŒ BAD: Dog inherits from Engine

    โœ” GOOD: Car has an Engine object

    ๐Ÿงฑ 14. Pattern: Behaviour Trees With Mixins

    Create classes with distinct abilities:

    Behaviour Trees With Mixins

    Composing game character abilities

    Try it Yourself ยป
    Python
    class MoveMixin:
        def move(self, direction):
            print(f"Moving {direction}")
    
    class AttackMixin:
        def attack(self, target):
            print(f"Attacking {target}!")
    
    class HealMixin:
        def heal(self, amount):
            print(f"Healing for {amount} HP")
    
    # Compose characters:
    class Warrior(MoveMixin, AttackMixin):
        pass
    
    class Mage(MoveMixin, HealMixin, AttackMixin):
        pass
    
    class Healer(MoveMixin, HealMixin):
        pass
    
    # Test the characters
    warrior = Warrior()
    warrior.move("forward"
    ...

    This is used in:

    • โœ” games
    • โœ” AI agents
    • โœ” simulations
    • โœ” robotics

    ๐Ÿงต 15. Pattern: Mechanical Mixins (Deep Automation)

    Advanced mixins generate code:

    Auto-generating Methods

    Mixins that automatically generate __repr__ and __eq__

    Try it Yourself ยป
    Python
    class AutoReprMixin:
        def __repr__(self):
            attrs = ", ".join(f"{k}={v!r}" for k, v in self.__dict__.items())
            return f"{self.__class__.__name__}({attrs})"
    
    class AutoEqMixin:
        def __eq__(self, other):
            if not isinstance(other, self.__class__):
                return False
            return self.__dict__ == other.__dict__
    
    # Plug them in:
    class User(AutoReprMixin, AutoEqMixin):
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
    u1 = User("Boopi
    ...

    Framework-level behaviour.

    ๐Ÿ“‹ Quick Reference โ€” Mixins & Multiple Inheritance

    ConceptWhat it does
    class C(A, B):Multiple inheritance โ€” inherits from A and B
    C.__mro__Method Resolution Order for lookups
    super()Call next class in MRO chain
    class LogMixin:Reusable behaviour added via inheritance
    isinstance(obj, Mixin)Check if mixin is applied

    ๐ŸŽ‰ Great work! You've completed this lesson.

    You can now compose reusable behaviours with mixins and reason about MRO โ€” the same pattern Django's class-based views use.

    Up next: Design Patterns โ€” apply proven solutions to common software architecture problems.

    Sign up for free to track which lessons you've completed and get learning reminders.

    Previous

    Cookie & Privacy Settings

    We use cookies to improve your experience, analyze traffic, and show personalized ads. You can manage your preferences below.

    By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising. You can customize your preferences or reject non-essential cookies.

    Privacy Policy โ€ข Terms of Service