DEV Community

Deepika Pusala
Deepika Pusala

Posted on

Week 04 - Task 1.3 : @dataclass, abstract base classes via the abc module & composition vs inheritance

Three more Python OOP tools that sound fancy but solve very ordinary problems: cutting boilerplate, enforcing rules on child classes, and choosing the right kind of relationship between objects.


🎁 @dataclass β€” Stop Writing Boilerplate

Every class that just stores data ends up looking the same:

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __repr__(self):
        return f"Student(name={self.name}, age={self.age})"
Enter fullscreen mode Exit fullscreen mode

@dataclass writes that for you:

from dataclasses import dataclass

@dataclass
class Student:
    name: str
    age: int
Enter fullscreen mode Exit fullscreen mode
student = Student("Deepika", 21)
print(student)
# Student(name='Deepika', age=21)
Enter fullscreen mode Exit fullscreen mode

Python auto-generates __init__(), __repr__(), and a few other useful methods based on the fields you declare.

Simple definition: @dataclass is a decorator that auto-generates common methods for classes whose main job is holding data.

Use it when: the class is basically a data container β€” think DTOs, config objects, records β€” not something with complex custom behavior.


🧱 Abstract Base Classes (abc) β€” Enforcing a Contract

Sometimes you don't want to give child classes an option to implement something β€” you want to force it.

Say you have several shapes, and every single one must have an area() method:

from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self):
        pass
Enter fullscreen mode Exit fullscreen mode

Shape is now an Abstract Base Class. @abstractmethod means:

"Every child class must provide its own area()."

class Circle(Shape):
    def area(self):
        return 3.14 * 5 * 5
Enter fullscreen mode Exit fullscreen mode

Try to instantiate Shape directly, though:

shape = Shape()   # ❌ TypeError
Enter fullscreen mode Exit fullscreen mode

Python refuses, because Shape still has an unimplemented abstract method.

Shape
 β”œβ”€β”€ Circle     β†’ must implement area()
 β”œβ”€β”€ Rectangle  β†’ must implement area()
 └── Triangle   β†’ must implement area()
Enter fullscreen mode Exit fullscreen mode

Simple definition: an Abstract Base Class defines methods that every child class is required to implement β€” a shared contract.


βš–οΈ @dataclass vs ABC β€” Different Jobs

@dataclass Abstract Base Class
Mainly stores data Defines rules/structure
Cuts boilerplate Forces child classes to implement methods
Auto-generates __init__, __repr__, etc. Uses @abstractmethod
Great for data models Great for shared interfaces

One-liners to remember:

  • @dataclass β†’ "I want to store data easily."
  • ABC β†’ "I want my child classes to follow a rule."

🧬 Composition vs Inheritance

This one trips people up conceptually more than syntactically. The cleanest way to hold it in your head:

Inheritance = IS-A Β· Composition = HAS-A

Inheritance (IS-A)

One class is a type of another.

class Animal:
    def eat(self):
        print("Eating")

class Dog(Animal):
    pass
Enter fullscreen mode Exit fullscreen mode

Dog IS-A Animal β€” so Dog inherits eat() for free.

Same logic: Car IS-A Vehicle, Circle IS-A Shape.

Composition (HAS-A)

One class contains another β€” it's built out of other objects, rather than being a specialized version of one.

class Engine:
    def start(self):
        print("Engine started")

class Car:
    def __init__(self):
        self.engine = Engine()

car = Car()
car.engine.start()
Enter fullscreen mode Exit fullscreen mode

A Car is not an Engine β€” it has an Engine. That relationship calls for composition, not inheritance.

A car also HAS-A Steering and HAS-A Battery β€” same pattern.

Side by Side

Inheritance Composition
IS-A relationship HAS-A relationship
Child inherits from parent Object contains another object
class Car(Vehicle) self.engine = Engine()
Reuse through hierarchy Reuse through objects
Can create tight coupling Usually more flexible

When to use which

  • Inheritance β†’ genuine IS-A relationship: Dog IS-A Animal, Car IS-A Vehicle, Circle IS-A Shape
  • Composition β†’ HAS-A relationship: Car HAS-A Engine, Computer HAS-A CPU, House HAS-A Room

Rule of thumb: if you're forcing an IS-A relationship just to reuse some code, it's usually a sign you actually wanted composition.


🎯 Quick Recap

Tool Solves
@dataclass Repetitive __init__/__repr__ boilerplate for data-holding classes
abc / @abstractmethod Forcing child classes to implement required methods
Inheritance "This is a specialized version of that"
Composition "This has a piece that does the work"

Top comments (0)