Mixins
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.
Part of the free Python course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
🔥 Mixins, Multiple Inheritance & OOP Patterns
This lesson teaches the REAL Python OOP system used by:
Framework
Common Mixins
Purpose
Django
LoginRequiredMixin, PermissionMixin
Authentication & authorization
SQLAlchemy
TimestampMixin, SerializerMixin
Database models & serialization
FastAPI
ModelConfigMixin
Configuration & validation
Scrapy
RetryMixin, LogMixin
Robustness & debugging
This is how large Python frameworks organise reusable behaviour at scale.
⭐ 1. What Are Mixins?
- ✔ a small class
- ✔ provides one specific behaviour
- ✔ not meant to be instantiated on its own
- ✔ used to "mix" extra features into other classes
Mixins = adding reusable abilities, not designing base types.
⭐ 2. Why Mixins Exist
Instead, they break features into "behaviour modules":
- ✔ LoggingMixin
- ✔ PermissionMixin
- ✔ RateLimitMixin
- ✔ CacheMixin
- ✔ TokenAuthMixin
- ✔ SerializerMixin
- ✔ RetryMixin
- ✔ EventEmitterMixin
This avoids the inheritance mess of shoving everything into one giant parent class.
⭐ 3. When NOT To Use Mixins
- ❌ complex logic
- ❌ core business functionality
- ❌ storage of critical state
- ❌ large method sets
- ❌ tightly coupled behaviour
- ✔ convenience methods
- ✔ add-on features
- ✔ small utilities
⚙️ 4. Multiple Inheritance — How Python Makes This Work
This determines which class Python checks first when calling a method.
⭐ 5. How to View the MRO
- ✔ method lookup
- ✔ attribute access
- ✔ super() behaviour
- ✔ complex inheritance chains
- ✔ how Python avoids the diamond problem
🔷 6. The Diamond Problem (and Python's solution)
- ✔ deterministic lookup order
- ✔ no ambiguity
- ✔ super() always moves to the next class in the hierarchy
⭐ 7. Why super() Matters in Multiple Inheritance
This allows cooperative multiple inheritance.
⚡ 8. Designing Cooperative Mixins
- ✔ call super()
- ✔ accept *args, **kwargs
- ✔ avoid breaking the chain
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.
Otherwise, your mixin may block other parents from initialising.
⭐ 10. Real-World Mixin Examples
🧠 11. Interface Mixins (Behaviour Contracts)
- ✔ you need consistency
- ✔ library expects a method to exist
- ✔ plugin systems
🔥 12. Multiple Inheritance for Role Composition
This is scalable for 10+ behaviour components.
🧩 13. Composition vs Inheritance (Critical Design Decision)
- • "is a" relationship
- • class hierarchy makes sense
- • polymorphic behaviour
- • "has a" relationship
- • behaviour shouldn't leak
- • state belongs to specific objects
🧱 14. Pattern: Behaviour Trees With Mixins
- ✔ simulations
🧵 15. Pattern: Mechanical Mixins (Deep Automation)
📋 Quick Reference — Mixins & Multiple Inheritance
Concept
What 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
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.
Practice quiz
What best describes a mixin?
- A large base class meant to be instantiated directly
- A function that returns a class
- A small class that provides one specific reusable behaviour, not meant to stand alone
- A module of unrelated helper functions
Answer: A small class that provides one specific reusable behaviour, not meant to stand alone. A mixin is a small class adding one capability that you mix into other classes; it is not instantiated on its own.
For 'class C(A, B): pass' where both A and B define greet(), which greet() runs for C()?
- A.greet, because A comes first in the MRO
- B.greet, because B is listed last
- Neither; it raises an error
- Both run in sequence
Answer: A.greet, because A comes first in the MRO. Python follows the MRO left to right, so A (listed first) is found before B.
What does C.__mro__ (or C.mro()) give you?
- The class's instance attributes
- A list of mixins only
- The class's metaclass
- The Method Resolution Order — the linear order Python searches for methods
Answer: The Method Resolution Order — the linear order Python searches for methods. __mro__ is the ordered tuple of classes Python checks when resolving attributes and methods.
What does Python use to compute a deterministic MRO and solve the diamond problem?
- Random ordering
- C3 linearization
- Depth-first left-to-right only
- Alphabetical ordering of class names
Answer: C3 linearization. CPython uses C3 linearization to produce a consistent, unambiguous MRO.
In multiple inheritance, what does super() actually do?
- Calls the NEXT class in the MRO chain
- Always calls the single direct parent class
- Calls the object base class directly
- Skips all parent classes
Answer: Calls the NEXT class in the MRO chain. super() delegates to the next class in the MRO, which is what makes cooperative inheritance work.
For 'class D(A, B, C):' where D.process calls super().process(), what is D's MRO order?
- D, C, B, A, object
- A, B, C, D, object
- D, A, B, C, object
- D, object, A, B, C
Answer: D, A, B, C, object. The MRO is D, A, B, C, object — left to right across the bases, then object.
For a cooperative mixin to not break the chain, its overriding method should:
- Never call super()
- Call super() and accept *args, **kwargs
- Return None immediately
- Define its own __init__ that ignores parents
Answer: Call super() and accept *args, **kwargs. Cooperative mixins call super() and pass through *args/**kwargs so every class in the MRO runs.
Why do mixins generally avoid defining __init__?
- Because __init__ is illegal in mixins
- Because mixins cannot store data ever
- Because __init__ makes them abstract
- Because it can break cooperative initialization across the MRO
Answer: Because it can break cooperative initialization across the MRO. A poorly written mixin __init__ can block other parents from initializing; if needed it must call super().__init__.
In 'class User(LoggingMixin, ValidationMixin, BaseModel)', calling user.save() that chains super() prints in what order?
- Saving to database!, Validating..., Logging save...
- Logging save..., Validating..., Saving to database!
- Validating..., Logging save..., Saving to database!
- Only Saving to database!
Answer: Logging save..., Validating..., Saving to database!. Following the MRO, LoggingMixin runs first, then ValidationMixin, then BaseModel does the real work.
When is composition ("has a") generally preferred over inheritance ("is a")?
- When there is a clear is-a relationship
- Whenever you need polymorphism
- When behaviour belongs to a specific object and shouldn't leak into a hierarchy
- Never; inheritance is always better
Answer: When behaviour belongs to a specific object and shouldn't leak into a hierarchy. Composition suits has-a relationships where state/behaviour belongs to a contained object rather than a subtype.