By the end of this lesson, you will understand how to define and use inner classes in Python to logically group related functionality while maintaining clear scope boundaries.
What it is
An inner class (also known as a nested class) is a class defined within the body of another class. It allows you to organize code by grouping classes that are closely related or only meaningful in the context of an outer class. The inner class does not have automatic access to the instance attributes of the outer class unless explicitly passed. Related terms include "nested functions" and "encapsulation."Why it matters
- Logical Grouping: Keeps related classes together, improving code readability and organization.
- Namespace Management: Prevents namespace pollution by hiding implementation details from the global scope.
- Encapsulation: Signals that the inner class is intended for internal use by the outer class.
- Dependency Clarity: Makes dependencies between classes explicit when one class relies heavily on another.
Syntax or steps
To create an inner class, simply define a class inside another class using standard indentation. You can instantiate the inner class directly via the outer class name or through an instance of the outer class if you pass references appropriately. Note that inner classes do not automatically inherit state from the outer class instance.Example
class Car:
def __init__(self, make):
self.make = make
# Instantiate the inner class with a reference to 'self' if needed
self.engine = self.Engine(make)
class Engine:
def __init__(self, car_make):
self.car_make = car_make
def start(self):
return f"{self.car_make} engine started."
# Usage
my_car = Car("Toyota")
print(my_car.engine.start())
Explanation:
1. Car is the outer class.
2. Engine is the inner class defined within Car.
3. In Car.__init__, we create an instance of Engine and pass the car's make to it. This demonstrates how to link inner class instances to outer class data manually.
4. We call start() on the engine instance to verify functionality.
Common mistakes
- Assuming Implicit Access: Inner classes cannot access outer class instance variables (
self) directly. You must pass them explicitly. - Overusing Inner Classes: If the inner class is used independently elsewhere, it should likely be a top-level class.
- Circular Dependencies: Avoid defining inner classes that rely on the outer class being fully initialized before they can function correctly without careful ordering.
- Pickling Issues: Instances of inner classes can sometimes cause issues with serialization libraries like
picklebecause they are not found at the module level.
When to use it
Compare inner classes with top-level helper classes. Use inner classes when the relationship is strictly hierarchical and the inner class has no meaning outside the outer class.| Feature | Inner Class | Top-Level Helper Class |
|---|---|---|
| Scope | Limited to outer class context | Global/Module level |
| Reusability | Low (tightly coupled) | High (independent) |
| Readability | Good for small, specific helpers | Better for complex logic |
Practice
Guided Exercise: Create a classLibrary with an inner class Book. The Book class should store a title and author. The Library class should have a method add_book that creates a new Book instance and stores it in a list.
Challenge: Modify the example so that the Book class knows which library it belongs to by passing the Library instance to its constructor. Print the library name when calling a method on the book.
Quick check
Can an inner class directly access theself variable of the outer class?
Answer: No. It must receive a reference to the outer instance explicitly, usually via the constructor.