DEV Community

abiud kipngetich
abiud kipngetich

Posted on

Mastering Object-Oriented Programming in Python: Classes, Pillars, and Robust Error Handling

1. Introduction

Object-Oriented Programming (OOP) organizes code around objects, which bundle data (attributes) and behavior (methods) together. Python supports OOP natively, and nearly everything in it, including integers, strings, and lists, in an object.

Using libraries and randint()

Python's standard library provides ready-made tools through the import statement. The random module is a common example:

import random 

roll = random.randint(1, 6)     # random integer from 1 to 6, inclusive 
print(roll)
Enter fullscreen mode Exit fullscreen mode

Here, random is a module (an object), and randint() is a method of it. You can also import a single function directly:

from random import randint 
print(randint(1, 100))
Enter fullscreen mode Exit fullscreen mode
  • Attributes are values stored on an object (e.g., car.color).

  • Methods are functions defined inside a class that act on the object (e.g., car.drive()).

2. Classes and Objects

A class is a blueprint. An object (or instance) is something built from that blueprint.

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

    def bark(self): 
        return f"{self.name} says woof!"  

mutina = Dog("Mutina", 3) 
print(mutina.bark())           # Mutina says woof!

Enter fullscreen mode Exit fullscreen mode

What is __init__? It is the constructor, a special method that runs automatically when an object is created. It sets up the object's initial state.
What is self? It refers to the specific instance being worked on. When you call mutina.bark(), Python passes mutina in as self, so each object keeps its own data.

3. Class Attributes vs. Instance Attributes

class Dog: 
    species = "Canis familiaris"    # class attribute (shared) 

    def __init__(self, name):  
        self.name = name            # instance attribute (unique) 

a = Dog("Rex") 
b = Dog("Bosco") 
print(a.species, b.species)       # shared value 
print(a.name, b.name)             # different values
Enter fullscreen mode Exit fullscreen mode
  • Class attributes belong to the class and are shared by all instances.

  • Instance attributes belong to one object and are defined via self (usually in __init__).

4. Methods

Python has three kinds of methods:

class Circle: 
    pi = 3.14159 

    def __init__(self, radius): 
        self.radius = radius 

    def area(self):           # instance method 
        return self.pi * self.radius ** 2 

    @classmethod 
    def unit(cls):            # class method 
        return cls(1) 

    @staticmethod 
    def is_valid(radius):      # static method 
        return radius > 0
Enter fullscreen mode Exit fullscreen mode
  • Instance methods use self and work with object data.

  • Class methods use cls and work with the class itself.

  • Static methods need neither; they are utility functions grouped with the class.

5. Parent and Child Classes

A parent (base) class provides shared features. A child (derived) class inherits them and can add or override behavior.

class Animal: 
    def __init__(self, name): 
        self.name = name 

    def speak(self): 
        return "Some sound" 

class Cat(Animal):                # Cat is the child of Animal 
    def __init__(self, name, indoor): 
        super().__init__(name)    # reuse the parent's setup 
        self.indoor = indoor 

    def speak(self):              # overide 
        return f"{self.name} says meow"
Enter fullscreen mode Exit fullscreen mode

super() gives the child access to the parent's methods.

6. The Four Pillars of OOP

Encapsulation bundles data and methods together and restricts direct access to internal state. Python uses naming conventions: _name (protected by convention) and __name (name-mangled, "private").

class BankAccount: 
    def __init__(self, balance): 
        self.__balance = balance 

    def deposit(self, amount): 
        if amount > 0: 
            self.__balance += amount 

    def get_balance(self):                 
        return self.__balance
Enter fullscreen mode Exit fullscreen mode

Inheritance lets a class reuse and extend another class's code, reducing duplication.
Polymorphism means different classes can respond to the same method call in their own way.

class Dog: 
    def speak(self): return "Woof" 

class Cat: 
    def speak(self): return "Meow" 

for pet in (Dog(), Cat()): 
    print(pet.speak())       # same call, different behavior
Enter fullscreen mode Exit fullscreen mode

Abstraction hides complexity and exposes only what is neccessary. Python implements it with abstract base classes:

from abc import ABC, abstractmethod 

class Shape(ABC): 
    @abstractmethod 
    def area(self): 
        pass 

class Square(Shape): 
    def __init__(self, side): 
        self.side = side 

    def area(self): 
        return self.side ** 2 
Enter fullscreen mode Exit fullscreen mode

Shape cannot be intantiated directly; every child must implement area().

7. Types of Python Errors

Type When it occurs Example
Syntax error Code breaks Python's grammar; the priogram won't start print("Hi"(missing parenthesis)
Runtime error Code is valid but fails while running 10 / 0
Logical error Code runs without crashing but produces wrong results Using + instead of * in a formula

Logical errors are the hardest to find because Python raises no warning. Testing and print() or debugger inspection are the best defenses.

8. Error Handling with try/except

try: 
    number = int(input("Enter a number: ")) 
    print(10 / number) 
except ValueError: 
    print("That is not a valid number.") 
except ZeroDivisionError: 
    print("Cannot divide by zero.") 
else: 
     print("Success!")       # runs only if no exception occurred 
finally: 
    print("Done.")           # always runs 

Enter fullscreen mode Exit fullscreen mode
  • try: code that might fail

  • except: handles a specific error

  • else: runs if nothing went wrong

  • finally: runs no matter what (ideal for cleanup)

You can also raise your own exceptions with raise ValueError("Invalid input").

9. Common Python Exceptions

ZeroDivisionError: dividing by zero.

print(5 / 0)
Enter fullscreen mode Exit fullscreen mode

ValueError: right type, inappropriate value.

int("abc")
Enter fullscreen mode Exit fullscreen mode

TypeError: an operation applied to the wrong type.

"5" + 3
Enter fullscreen mode Exit fullscreen mode

NameError: using a variable that hasn't been defined.

print(undefined_var)
Enter fullscreen mode Exit fullscreen mode

IndexError: accessing a list position that doesn't exist.

items = [1, 2, 3] 
print(items[5])
Enter fullscreen mode Exit fullscreen mode

FileNotFoundError: opening a file that doesn't exist.

open("missing.txt")
Enter fullscreen mode Exit fullscreen mode

Conclusion

Object-oriented programming gives Python developers a clean way to model real-world problems: classes define structure, objects hold state, and the four pillars keep code organized, reusable, and secure. Paired with disciplined error handling, which anticipates syntax, runtime, and logical failures and catches common exceptions gracefully, these skills form the foundation of professional, maintainable Python code.

Top comments (0)