# The Inheritance Gallery: Parent and Child Classes

Timothy's library had grown beyond simple books. He now cataloged audiobooks, ebooks, and rare manuscripts—each with unique attributes. Audiobooks had narrators and durations. Ebooks had file formats and download links. Manuscripts had preservation conditions and historical significance.

His first attempt created separate classes with duplicated code:

```python
class Book:
    def __init__(self, title, author, year):
        self.title = title
        self.author = author
        self.year = year

class Audiobook:
    def __init__(self, title, author, year, narrator, duration_minutes):
        self.title = title        # Duplicated
        self.author = author      # Duplicated
        self.year = year          # Duplicated
        self.narrator = narrator
        self.duration_minutes = duration_minutes

class Ebook:
    def __init__(self, title, author, year, file_format, download_url):
        self.title = title        # Duplicated
        self.author = author      # Duplicated
        self.year = year          # Duplicated
        self.file_format = file_format
        self.download_url = download_url
```

Margaret found him writing the same initialization code for the third time. "You're repeating yourself," she observed. "Come to the Inheritance Gallery—where specialized blueprints inherit from general ones."

## The Parent-Child Relationship

Margaret showed Timothy inheritance:

```python
class Book:
    def __init__(self, title, author, year):
        self.title = title
        self.author = author
        self.year = year
    
    def get_summary(self):
        return f'"{self.title}" by {self.author} ({self.year})'

class Audiobook(Book):  # Inherits from Book
    def __init__(self, title, author, year, narrator, duration_minutes):
        super().__init__(title, author, year)  # Call parent's __init__
        self.narrator = narrator
        self.duration_minutes = duration_minutes

# Create an audiobook
dune_audio = Audiobook("Dune", "Herbert", 1965, "Scott Brick", 1233)

# Audiobook has Book's attributes and methods
print(dune_audio.title)          # "Dune"
print(dune_audio.narrator)       # "Scott Brick"
print(dune_audio.get_summary())  # "Dune" by Herbert (1965)
```

"The `Audiobook` class inherits from `Book`," Margaret explained. "It gets all of Book's attributes and methods automatically. We only add what's unique to audiobooks."

## Understanding super()

Timothy was curious about `super()`:

```python
class Book:
    def __init__(self, title, author, year):
        self.title = title
        self.author = author
        self.year = year

class Audiobook(Book):
    def __init__(self, title, author, year, narrator, duration_minutes):
        # super() finds the parent class and calls its method
        super().__init__(title, author, year)
        # Now add audiobook-specific attributes
        self.narrator = narrator
        self.duration_minutes = duration_minutes
```

"`super()` calls the parent class's method," Margaret explained. "It handles the shared initialization, then you add specialized attributes. This eliminates duplication."

## Method Overriding

Timothy learned child classes could replace parent methods:

```python
class Book:
    def __init__(self, title, author, year):
        self.title = title
        self.author = author
        self.year = year
    
    def get_summary(self):
        return f'"{self.title}" by {self.author} ({self.year})'

class Audiobook(Book):
    def __init__(self, title, author, year, narrator, duration_minutes):
        super().__init__(title, author, year)
        self.narrator = narrator
        self.duration_minutes = duration_minutes
    
    # Override parent's method
    def get_summary(self):
        hours = self.duration_minutes / 60
        return f'"{self.title}" by {self.author} ({self.year}) - Narrated by {self.narrator}, {hours:.1f} hours'

dune = Book("Dune", "Herbert", 1965)
dune_audio = Audiobook("Dune", "Herbert", 1965, "Scott Brick", 1233)

print(dune.get_summary())
# "Dune" by Herbert (1965)

print(dune_audio.get_summary())
# "Dune" by Herbert (1965) - Narrated by Scott Brick, 20.6 hours
```

"The child class *overrides* the parent's method," Margaret noted. "When you call `get_summary()` on an `Audiobook`, Python uses the audiobook's version, not the book's."

## Extending Parent Methods

Timothy discovered he could call the parent's method and then add to it:

```python
class Audiobook(Book):
    def __init__(self, title, author, year, narrator, duration_minutes):
        super().__init__(title, author, year)
        self.narrator = narrator
        self.duration_minutes = duration_minutes
    
    def get_summary(self):
        # Call parent's method, then extend it
        base_summary = super().get_summary()
        hours = self.duration_minutes / 60
        return f'{base_summary} - Narrated by {self.narrator}, {hours:.1f} hours'
```

"This is better than duplicating code," Margaret explained. "You reuse the parent's logic and add specialized behavior."

## The isinstance Check

Margaret showed Timothy how to check object types:

```python
dune = Book("Dune", "Herbert", 1965, 412)
dune_audio = Audiobook("Dune", "Herbert", 1965, "Scott Brick", 1233)

# isinstance checks the hierarchy
print(isinstance(dune, Book))        # True
print(isinstance(dune_audio, Book))  # True - audiobook IS a book
print(isinstance(dune_audio, Audiobook))  # True
print(isinstance(dune, Audiobook))   # False - book is NOT an audiobook

# type checks exact type only
print(type(dune_audio) == Book)      # False - not exactly a Book
print(type(dune_audio) == Audiobook) # True - exactly an Audiobook
```

"An `Audiobook` *is a* `Book`," Margaret explained. "Use `isinstance()` when checking types - it respects inheritance. Use `type()` only when you need the exact class."

## Method Resolution Order: How Python Finds Methods

Timothy wondered how Python decided which method to call when multiple classes were involved. Margaret showed him the Method Resolution Order:

```python
class Book:
    def get_info(self):
        return "Book info"

class Audiobook(Book):
    def get_info(self):
        return "Audiobook info"

audiobook = Audiobook("Dune", "Herbert", 1965, "Scott Brick", 1233)

# Python searches classes in a specific order
print(Audiobook.__mro__)
# (<class 'Audiobook'>, <class 'Book'>, <class 'object'>)

# Order: Check Audiobook first, then Book, then object
# Every class inherits from object
```

"Python searches left-to-right, starting with the child class," Margaret explained. "When you call a method, Python checks `Audiobook` first, then `Book`, then `object`. This is why child methods override parent methods."

## When You Don't Need to Override **init**

Timothy learned he didn't always need to override initialization:

```python
class SpecialBook(Book):
    # No __init__ override - uses parent's automatically
    
    def get_special_status(self):
        return f'"{self.title}" is a special edition!'

# Uses Book's __init__ automatically
special = SpecialBook("Dune", "Herbert", 1965, 412)
print(special.get_special_status())  # Works!
```

"If you don't override `__init__`, the child class uses the parent's," Margaret noted. "Only override when you need additional attributes."

## Real-World Example: Library Catalog System

Margaret demonstrated a practical hierarchy:

```python
class Book:
    def __init__(self, title, author, year, pages):
        self.title = title
        self.author = author
        self.year = year
        self.pages = pages
        self.is_checked_out = False
    
    def checkout(self):
        if self.is_checked_out:
            return False
        self.is_checked_out = True
        return True
    
    def return_item(self):
        self.is_checked_out = False
    
    def get_reading_time(self):
        return self.pages * 2  # 2 minutes per page

class Audiobook(Book):
    def __init__(self, title, author, year, narrator, duration_minutes):
        super().__init__(title, author, year, pages=0)  # Audiobooks have no pages
        self.narrator = narrator
        self.duration_minutes = duration_minutes
    
    def get_reading_time(self):
        # Override - return listening time instead
        return self.duration_minutes

class Ebook(Book):
    def __init__(self, title, author, year, pages, file_format, file_size_mb):
        super().__init__(title, author, year, pages)
        self.file_format = file_format
        self.file_size_mb = file_size_mb
    
    def get_download_info(self):
        return f'{self.file_format} format, {self.file_size_mb}MB'

# All types can be checked out
catalog = [
    Book("Dune", "Herbert", 1965, 412),
    Audiobook("1984", "Orwell", 1949, "Simon Prebble", 720),
    Ebook("Foundation", "Asimov", 1951, 255, "EPUB", 2.4)
]

# Polymorphism - treat all items the same way
for item in catalog:
    print(f'{item.title}: {item.get_reading_time()} minutes')
    item.checkout()
```

## When to Use Inheritance

Margaret emphasized when inheritance made sense:

**Use inheritance when:**

* There's a clear "is-a" relationship (audiobook IS a book)
    
* Child classes share substantial behavior with the parent
    
* You want polymorphism (treating different types uniformly)
    
* The hierarchy is stable and unlikely to change
    

**Don't use inheritance when:**

* Relationship is "has-a" (car HAS an engine, not car IS an engine)
    
* You only need a few methods from another class
    
* The hierarchy becomes complex (more than 2-3 levels deep)
    
* Composition would be clearer
    

## Composition vs Inheritance

Margaret showed Timothy the alternative to inheritance:

```python
# Inheritance approach
class Audiobook(Book):
    def __init__(self, title, author, year, narrator, duration_minutes):
        super().__init__(title, author, year)
        self.narrator = narrator
        self.duration_minutes = duration_minutes

# Composition approach - "has-a" relationship
class Audiobook:
    def __init__(self, title, author, year, narrator, duration_minutes):
        self.book_info = Book(title, author, year)  # Has a Book
        self.narrator = narrator
        self.duration_minutes = duration_minutes
    
    def get_summary(self):
        return f'{self.book_info.get_summary()} - Narrated by {self.narrator}'
```

"Composition means containing another object," Margaret explained. "Favor composition over inheritance when the relationship isn't clearly 'is-a'."

## Multiple Inheritance: A Brief Look

Timothy glimpsed a more complex pattern:

```python
class Book:
    def __init__(self, title, author, year, pages=0, **kwargs):
        super().__init__(**kwargs)  # Pass remaining arguments up the chain
        self.title = title
        self.author = author
        self.year = year
        self.pages = pages

class AudioContent:
    def __init__(self, narrator, duration_minutes, **kwargs):
        super().__init__(**kwargs)
        self.narrator = narrator
        self.duration_minutes = duration_minutes
    
    def get_audio_info(self):
        hours = self.duration_minutes / 60
        return f'Narrated by {self.narrator}, {hours:.1f} hours'

class DigitalContent:
    def __init__(self, file_format, file_size_mb, **kwargs):
        super().__init__(**kwargs)
        self.file_format = file_format
        self.file_size_mb = file_size_mb
    
    def get_file_info(self):
        return f'{self.file_format}, {self.file_size_mb}MB'

class Audiobook(Book, AudioContent, DigitalContent):
    def __init__(self, title, author, year, narrator, duration_minutes, file_format, file_size_mb):
        super().__init__(
            title=title,
            author=author,
            year=year,
            narrator=narrator,
            duration_minutes=duration_minutes,
            file_format=file_format,
            file_size_mb=file_size_mb
        )

# Has attributes and methods from all parent classes
audiobook = Audiobook("Dune", "Herbert", 1965, "Scott Brick", 1233, "MP3", 450)
print(audiobook.title)           # From Book
print(audiobook.get_audio_info()) # From AudioContent
print(audiobook.get_file_info())  # From DigitalContent
```

"Multiple inheritance lets a class inherit from multiple parents," Margaret cautioned. "Notice the `**kwargs` pattern - it's called cooperative inheritance. Each parent's `__init__` calls `super()`, passing remaining arguments up the chain. But this is complex - usually composition is clearer."

## Timothy's Inheritance Wisdom

Through exploring the Inheritance Gallery, Timothy learned essential principles:

**Inheritance creates "is-a" relationships**: Child classes are specialized versions of parent classes.

**super() calls parent methods**: Eliminates code duplication in initialization and methods.

**Method overriding replaces parent behavior**: Child classes can provide specialized implementations.

**Extending methods reuses parent logic**: Call parent method with `super()`, then add more.

**Use isinstance() for type checking**: It respects inheritance hierarchy, unlike `type()`.

**Method Resolution Order (MRO) determines lookup**: Python searches child first, then parents, then object.

**Not all methods need overriding**: If parent's `__init__` is sufficient, don't override it.

**Polymorphism treats types uniformly**: Different classes can respond to the same method calls.

**Favor composition over inheritance**: "Has-a" relationships often clearer than "is-a".

**Keep hierarchies shallow**: More than 2-3 levels becomes hard to maintain.

**Multiple inheritance requires cooperation**: Use `**kwargs` pattern with `super()` for correct behavior.

**Multiple inheritance is complex**: Composition is usually simpler and clearer.

**Inheritance is for shared behavior**: Not just for code reuse—composition can do that too.

Timothy had discovered how to build specialized blueprints from general ones—creating hierarchies where audiobooks, ebooks, and manuscripts could all be treated as books while maintaining their unique characteristics. The Inheritance Gallery had revealed the power and the limits of parent-child relationships in object-oriented design.

---

*Aaron Rose is a software engineer and technology writer at* [*tech-reader.blog*](https://www.tech-reader.blog) *and the author of* [*Think Like a Genius*](https://amazon.com/author/aaron.rose)*.*
