# The OOP Pillars Exam

> Four principles, one class hierarchy - show you know all of them.

Canonical URL: <https://datadriven.io/problems/the_oop_pillars_exam>

Domain: Python · Difficulty: medium · Seniority: L3

## Problem

Given a list of [animal_type, name] pairs, instantiate the appropriate subclass of an abstract Animal class (with an abstract speak()). 'dog' subclass speaks 'Woof!'; 'cat' subclass speaks 'Meow!'. For each instance, return the string '{name} says: {sound}'. Implement inheritance and polymorphism correctly.

## Worked solution and explanation

### Why this problem exists in real interviews

This tests whether candidates understand the **four pillars of OOP** (encapsulation, inheritance, polymorphism, abstraction) and can implement them in Python using `abc.ABC` and `abstractmethod`. It is a design question disguised as a coding exercise.

---

### Break down the requirements

#### Step 1: Define an abstract base class

Use `abc.ABC` and `@abstractmethod` to define `Animal` with an abstract `speak()` method. This enforces that subclasses implement `speak()`.

#### Step 2: Implement concrete subclasses

Create `Dog` and `Cat` that inherit from `Animal` and provide their own `speak()` implementations.

#### Step 3: Encapsulate the name

Store the name as a private attribute (using underscore convention) and optionally expose it via a property.

#### Step 4: Demonstrate polymorphism

Iterate over a list of mixed animal instances and call `speak()` on each, showing that the correct implementation is invoked.

---

### The solution

**ABC with concrete subclasses and polymorphic dispatch**

```python
from abc import ABC, abstractmethod
class Animal(ABC):
    def __init__(self, name):
        self._name = name
    @abstractmethod
    def speak(self):
        pass
class Dog(Animal):
    def speak(self):
        return self._name + ' says Woof'
class Cat(Animal):
    def speak(self):
        return self._name + ' says Meow'
def collect_sounds(animals):
    result = []
    for animal in animals:
        result.append(animal.speak())
    return result
```

> **Time and Space Complexity**
>
> **Time:** O(n) where n is the number of animals.
> 
> **Space:** O(n) for the result list.

> **Interviewers Watch For**
>
> Can you name all four pillars and point to where each one appears in your code? Abstraction: the ABC. Encapsulation: `_name`. Inheritance: Dog/Cat extend Animal. Polymorphism: `animal.speak()` dispatches to the correct subclass.

> **Common Pitfall**
>
> Forgetting to import `ABC` and `abstractmethod`. Without `@abstractmethod`, Python will not enforce that subclasses implement `speak()`, defeating the purpose of the abstract class.

---

## Common follow-up questions

- What happens if you try to instantiate Animal directly? _(Tests understanding that ABCs raise TypeError if instantiated.)_
- How would you add a new animal type without modifying existing code? _(Tests the Open/Closed Principle.)_
- What is the difference between single underscore and double underscore in Python? _(Tests name mangling vs convention-based privacy.)_
- How does Python's duck typing relate to polymorphism? _(Tests awareness that Python does not require inheritance for polymorphic behavior.)_

## Related

- [All practice problems](https://datadriven.io/problems)
- [Mock interview mode](https://datadriven.io/interview/the_oop_pillars_exam)
- [Python Interview Questions](https://datadriven.io/python-interview-questions)
- [Data Engineering Interview Prep Guide](https://datadriven.io/data-engineer-interview-prep)
- [Daily Challenge](https://datadriven.io/daily)

---

Source: DataDriven (https://datadriven.io). 100% free data engineering interview prep. Live code execution against Postgres 16, Python 3.11, and Spark sandboxes. No paywall, no premium tier, no signup gate.