Tutorials Logic
Tutorials Logic, IN info@tutorialslogic.com
Navigation
Home About Us Contact Us Blogs FAQs
Tutorials
All Tutorials
Services
Academic Projects Resume Writing Website Development
Practice
Quiz Challenge Interview Questions Certification Practice
Tools
Online Compiler JSON Formatter Regex Tester CSS Unit Converter Color Picker
Compiler Tools

Python OOP Tutorial - Classes, Objects, Inheritance Examples

Object-Oriented Programming

Python is an object-oriented language. A class is a blueprint for creating objects. An object is an instance of a class with its own data (attributes) and behavior (methods).

Defining a Class

Basic Class
class Dog:
    # Class attribute - shared by all instances
    species = "Canis familiaris"

    # __init__ is the constructor
    def __init__(self, name: str, age: int):
        # Instance attributes - unique to each object
        self.name = name
        self.age = age

    # Instance method
    def bark(self) -> str:
        return f"{self.name} says: Woof!"

    def describe(self) -> str:
        return f"{self.name} is {self.age} years old"

# Create objects (instances)
dog1 = Dog("Buddy", 3)
dog2 = Dog("Max", 5)

print(dog1.bark())       # Buddy says: Woof!
print(dog2.describe())   # Max is 5 years old
print(dog1.species)      # Canis familiaris
print(Dog.species)       # Canis familiaris (via class)

Special (Dunder) Methods

Methods with double underscores like __init__, __str__, __repr__ are called dunder (magic) methods. They define how objects behave with built-in operations.

Dunder Methods
class Point:
    def __init__(self, x: float, y: float):
        self.x = x
        self.y = y

    def __str__(self) -> str:
        """Called by print() and str()"""
        return f"Point({self.x}, {self.y})"

    def __repr__(self) -> str:
        """Called in REPL and for debugging"""
        return f"Point(x={self.x}, y={self.y})"

    def __add__(self, other: "Point") -> "Point":
        """Called by + operator"""
        return Point(self.x + other.x, self.y + other.y)

    def __eq__(self, other: "Point") -> bool:
        """Called by == operator"""
        return self.x == other.x and self.y == other.y

    def __len__(self) -> int:
        """Called by len()"""
        import math
        return int(math.sqrt(self.x**2 + self.y**2))

p1 = Point(1, 2)
p2 = Point(3, 4)

print(p1)           # Point(1, 2)
print(p1 + p2)      # Point(4, 6)
print(p1 == p2)     # False
print(p1 == Point(1, 2))  # True

Inheritance

A child class inherits attributes and methods from a parent class. Use super() to call the parent's methods.

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

    def speak(self) -> str:
        return f"{self.name} makes a sound"

class Dog(Animal):
    def speak(self) -> str:
        return f"{self.name} says: Woof!"

class Cat(Animal):
    def speak(self) -> str:
        return f"{self.name} says: Meow!"

class GuideDog(Dog):
    def __init__(self, name: str, owner: str):
        super().__init__(name)   # call parent __init__
        self.owner = owner

    def describe(self) -> str:
        return f"{self.name} guides {self.owner}"

animals = [Dog("Buddy"), Cat("Whiskers"), GuideDog("Rex", "Alice")]
for animal in animals:
    print(animal.speak())

# isinstance and issubclass
print(isinstance(animals[0], Dog))     # True
print(isinstance(animals[0], Animal))  # True
print(issubclass(Dog, Animal))         # True

Class Methods, Static Methods & Properties

Decorators
class Circle:
    PI = 3.14159

    def __init__(self, radius: float):
        self._radius = radius   # _ prefix = "private by convention"

    @property
    def radius(self) -> float:
        """Getter"""
        return self._radius

    @radius.setter
    def radius(self, value: float):
        """Setter with validation"""
        if value < 0:
            raise ValueError("Radius cannot be negative")
        self._radius = value

    @property
    def area(self) -> float:
        return Circle.PI * self._radius ** 2

    @classmethod
    def from_diameter(cls, diameter: float) -> "Circle":
        """Alternative constructor"""
        return cls(diameter / 2)

    @staticmethod
    def is_valid_radius(r: float) -> bool:
        """Utility - doesn't need self or cls"""
        return r >= 0

c = Circle(5)
print(c.area)          # 78.53975
c.radius = 10          # uses setter
print(c.radius)        # 10

c2 = Circle.from_diameter(20)
print(c2.radius)       # 10.0

print(Circle.is_valid_radius(-1))  # False

Dataclasses (Python 3.7+)

The @dataclass decorator auto-generates __init__, __repr__, and __eq__ for you.

Dataclasses
from dataclasses import dataclass, field

@dataclass
class Student:
    name: str
    age: int
    grades: list[int] = field(default_factory=list)

    def average(self) -> float:
        return sum(self.grades) / len(self.grades) if self.grades else 0.0

s = Student("Alice", 20, [90, 85, 92])
print(s)              # Student(name='Alice', age=20, grades=[90, 85, 92])
print(s.average())    # 89.0
print(s == Student("Alice", 20, [90, 85, 92]))  # True

# Frozen dataclass (immutable)
@dataclass(frozen=True)
class Point:
    x: float
    y: float

p = Point(1.0, 2.0)
# p.x = 5  # FrozenInstanceError!

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.