Skip to content

Object-Oriented Programming (OOP) Concepts

A beginner-friendly guide to the main Object-Oriented Programming concepts used in Python.

This document explains: - Classes - Objects - Inheritance - Encapsulation - Polymorphism - Abstraction - Composition vs Inheritance

These concepts are heavily used in: - game development - APIs - large Python applications - design patterns - 42 Python modules


What is OOP?

Object-Oriented Programming (OOP) is a programming style based on objects.

Objects: - store data - contain behavior - interact with each other

OOP helps organize large projects into reusable and maintainable structures.


Classes

A class is a blueprint for creating objects.


Example

class Duck:

    def quack(self) -> None:
        print("Quack!")

Creating an Object

duck = Duck()

duck.quack()

Output:

Quack!

Attributes

Attributes store data inside objects.


Example

class Player:

    def __init__(self, name: str) -> None:
        self.name = name

init()

__init__() is called automatically when an object is created.

It initializes the object attributes.


Creating the Object

player = Player("Sara")

Accessing Attributes

print(player.name)

Output:

Sara

Methods

Methods are functions inside classes.


Example

class Enemy:

    def attack(self) -> None:
        print("Enemy attacks!")

Inheritance

Inheritance allows one class to reuse another class.

A child class inherits: - attributes - methods - behavior

from a parent class.


Example

class Animal:

    def speak(self) -> None:
        print("Some sound")


class Dog(Animal):

    def bark(self) -> None:
        print("Woof!")

Using Inheritance

dog = Dog()

dog.speak()
dog.bark()

Output:

Some sound
Woof!

Why Use Inheritance?

Inheritance: - reduces duplicated code - improves organization - allows shared behavior


Overriding Methods

Child classes can replace parent behavior.


Example

class Animal:

    def speak(self) -> None:
        print("Animal sound")


class Cat(Animal):

    def speak(self) -> None:
        print("Meow")

Result

cat = Cat()

cat.speak()

Output:

Meow

This is called method overriding.


Polymorphism

Polymorphism means: - different objects - same method name - different behavior


Example

class Dog:

    def speak(self) -> None:
        print("Woof")


class Cat:

    def speak(self) -> None:
        print("Meow")

Using Polymorphism

animals = [Dog(), Cat()]

for animal in animals:
    animal.speak()

Output:

Woof
Meow

Same method: - different implementations


Encapsulation

Encapsulation means protecting internal object data.

Objects should control access to their own state.


Protected Attributes

Convention: - _name

Means: - "internal use" - should not be modified directly


Private Attributes

Convention: - __name

Makes direct access harder.


Example

class BankAccount:

    def __init__(self) -> None:
        self.__balance = 0

Access Problem

account = BankAccount()

print(account.__balance)

This raises an error.


Controlled Access

Use methods instead.


Example

class BankAccount:

    def __init__(self) -> None:
        self.__balance = 0

    def deposit(self, amount: int) -> None:
        self.__balance += amount

    def get_balance(self) -> int:
        return self.__balance

Abstraction

Abstraction hides implementation details.

The user interacts with: - simple interfaces - not internal complexity


Example

class CoffeeMachine:

    def make_coffee(self) -> None:
        print("Making coffee...")

The user: - presses a button - does not care about internal machine logic


Abstract Classes

Python supports abstract classes using ABC.


Example

from abc import ABC, abstractmethod


class Creature(ABC):

    @abstractmethod
    def attack(self) -> None:
        pass

Child Implementation

class Dragon(Creature):

    def attack(self) -> None:
        print("Fire breath!")

Why Use Abstraction?

Abstraction: - forces structure - improves consistency - defines required behavior

Very useful in: - game systems - factories - APIs - strategy patterns


Composition

Composition means: - objects contain other objects

Instead of inheriting behavior.


Example

class Engine:

    def start(self) -> None:
        print("Engine started")


class Car:

    def __init__(self) -> None:
        self.engine = Engine()

Using Composition

car = Car()

car.engine.start()

Composition vs Inheritance

Inheritance

Represents: - "is-a" relationship

Example:

Dog is an Animal

Composition

Represents: - "has-a" relationship

Example:

Car has an Engine

Which is Better?

Composition is often safer and more flexible.

Inheritance is useful when: - behavior is truly shared

Composition is useful when: - objects collaborate together


Real 42 Examples

Inheritance

class Enemy(GameObject):

Composition

class Game:
    self.player = Player()

Polymorphism

enemy.attack()
boss.attack()

Different enemies: - same method - different behavior


Common OOP Benefits

  • Better code organization
  • Reusability
  • Easier maintenance
  • Cleaner architecture
  • Scalability for large projects

Common OOP Problems

Bad OOP design may cause: - overly deep inheritance trees - tightly coupled systems - hard debugging - unnecessary complexity


Best Practices

  • Prefer composition over excessive inheritance
  • Keep classes focused on one responsibility
  • Use meaningful class names
  • Avoid giant classes
  • Encapsulate sensitive data
  • Use abstraction for shared interfaces

Summary Table

Concept Meaning
Class Blueprint for objects
Object Instance of a class
Inheritance Reuse behavior from another class
Encapsulation Protect internal data
Polymorphism Same method, different behavior
Abstraction Hide implementation details
Composition Objects containing objects

Final Notes

OOP is one of the most important programming paradigms in Python.

Understanding these concepts helps when building: - games - MLX projects - APIs - parsers - large applications - design pattern systems

Strong OOP foundations make code: - cleaner - safer - easier to scale