Skip to content
πŸ’» 🧠 Code 1001 > πŸ“š Learning Materials > 🐍 Python > Python Classes, OOP & Context Managers: Complete Guide

Python Classes, OOP & Context Managers: Complete Guide

1. Classes in Python

Class Structure

class ClassName:
    def __init__(self, param1, param2):
        self.param1 = param1
        self.param2 = param2

    def method(self):
        return f'{self.param1} and {self.param2}'

Key Points:

  • __init__: constructor to initialize object attributes.
  • self: reference to the current instance.
  • Attributes: defined via self, accessible in all methods.
  • Methods: operate on object data.

Creating Objects

class Car:
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year

    def description(self):
        return f'{self.year} {self.make} {self.model}'

my_car = Car('Toyota', 'Corolla', 2020)
print(my_car.description())  # Output: 2020 Toyota Corolla

Types of Methods

  1. Instance Methods – operate on objects (self).
  2. Class Methods – operate on the class itself (cls) with @classmethod.
  3. Static Methods – independent of instance or class with @staticmethod.

Inheritance

class Animal:
    def speak(self):
        return 'Animal sound'

class Dog(Animal):
    def speak(self):
        return 'Woof'

Polymorphism

class Cat(Animal):
    def speak(self):
        return 'Meow'

cat = Cat()
print(cat.speak())  # Output: Meow
  • Same method name works differently depending on object type.

Encapsulation

class Car:
    def __init__(self, make, model):
        self._make = make  # Protected
        self._model = model

    def get_make(self):
        return self._make

    def set_make(self, make):
        self._make = make

Magic Methods & Destructor

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

    def __repr__(self):
        return f'Point({self.x}, {self.y})'

p = Point(3, 4)
print(p)  # Output: Point(3, 4)

ASCII Diagram: Inheritance & Polymorphism

       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”
       β”‚ Animal  β”‚
       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
       β”‚ speak() β”‚
       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
            β–²
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚                β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Dog    β”‚      β”‚  Cat    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ speak() β”‚      β”‚ speak() β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

2. Context Managers in Python

Context managers allow you to allocate and release resources automatically, ensuring clean-up even when errors occur.

Using @contextmanager

from contextlib import contextmanager

@contextmanager
def my_context():
    print("Entering context")
    try:
        yield "Resource"
    finally:
        print("Exiting context")

Usage:

with my_context() as res:
    print("Inside context:", res)

Capturing stdout/stderr and Tee

Python allows capturing stdout, stderr, or both, and even simultaneously displaying and capturing output using a Tee pattern.


3. Full Python Example: oop_and_context.py

"""
oop_and_context.py

Comprehensive examples of Python classes, OOP principles, and context managers.
Includes:
- Class definitions, inheritance, polymorphism, encapsulation
- Instance, class, and static methods
- Magic methods and destructors
- Context managers with @contextmanager
- stdout, stderr, combined output capture
- Tee pattern: simultaneous capture and display
- Class-based context manager for best practices
"""

import sys
import io
from contextlib import contextmanager

# ==========================
# Part 1: Classes & OOP
# ==========================

class Animal:
    """Base class for animals."""
    def speak(self):
        return 'Animal sound'

class Dog(Animal):
    def speak(self):
        return 'Woof'

class Cat(Animal):
    def speak(self):
        return 'Meow'

class Car:
    """Example class with encapsulation."""
    def __init__(self, make, model, year=None):
        self._make = make
        self._model = model
        self.year = year

    def get_make(self):
        return self._make

    def set_make(self, make):
        self._make = make

    def description(self):
        if self.year:
            return f'{self.year} {self._make} {self._model}'
        return f'{self._make} {self._model}'

class Point:
    """Class demonstrating magic methods."""
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        return f'Point({self.x}, {self.y})'

# ==========================
# Part 2: Context Managers
# ==========================

@contextmanager
def my_context():
    print("Entering context")
    try:
        yield "Resource"
    finally:
        print("Exiting context")

@contextmanager
def capture_stdout():
    old_stdout = sys.stdout
    sys.stdout = buffer = io.StringIO()
    try:
        yield buffer
    finally:
        sys.stdout = old_stdout

@contextmanager
def capture_stderr():
    old_stderr = sys.stderr
    sys.stderr = buffer = io.StringIO()
    try:
        yield buffer
    finally:
        sys.stderr = old_stderr

@contextmanager
def capture_output():
    old_stdout = sys.stdout
    old_stderr = sys.stderr
    sys.stdout = sys.stderr = buffer = io.StringIO()
    try:
        yield buffer
    finally:
        sys.stdout = old_stdout
        sys.stderr = old_stderr

class Tee(io.StringIO):
    """Capture and display output simultaneously."""
    def __init__(self, original):
        super().__init__()
        self.original = original

    def write(self, text):
        self.original.write(text)
        super().write(text)

    def flush(self):
        self.original.flush()

@contextmanager
def capture_stdout_tee():
    old_stdout = sys.stdout
    sys.stdout = tee = Tee(old_stdout)
    try:
        yield tee
    finally:
        sys.stdout = old_stdout

# ==========================
# Part 3: Best Practices
# ==========================

class OutputCapture:
    """Class-based context manager for capturing stdout."""
    def __init__(self):
        self._buffer = io.StringIO()
        self._old_stdout = None

    def __enter__(self):
        self._old_stdout = sys.stdout
        sys.stdout = self._buffer
        return self._buffer

    def __exit__(self, exc_type, exc_val, exc_tb):
        sys.stdout = self._old_stdout
        return False  # propagate exceptions

# ==========================
# Part 4: Demonstrations
# ==========================

def demo_classes():
    print("\n--- Classes Demo ---")
    dog = Dog()
    cat = Cat()
    print("Dog says:", dog.speak())
    print("Cat says:", cat.speak())

    my_car = Car('Toyota', 'Corolla', 2020)
    print("Car description:", my_car.description())
    my_car.set_make('Honda')
    print("Updated make:", my_car.get_make())

    point = Point(3, 4)
    print("Point:", point)

def demo_context_managers():
    print("\n--- Context Managers Demo ---")
    with my_context() as res:
        print("Inside context:", res)

    with capture_stdout() as out:
        print("Captured stdout")
    print("Output captured:", out.getvalue().strip())

    with capture_stderr() as err:
        print("This goes to stdout")
        sys.stderr.write("Error message\n")
    print("Error captured:", err.getvalue().strip())

    with capture_output() as out_all:
        print("Stdout inside combined capture")
        sys.stderr.write("Stderr inside combined capture\n")
    print("Combined output:", out_all.getvalue().strip())

    with capture_stdout_tee() as tee_out:
        print("Visible AND captured via Tee")
    print("Tee buffer content:", tee_out.getvalue().strip())

    with OutputCapture() as class_capture:
        print("Captured using class-based context manager")
    print("Class-based capture:", class_capture.getvalue().strip())

# ==========================
# Main execution
# ==========================

if __name__ == "__main__":
    demo_classes()
    demo_context_managers()

Leave a Reply

Your email address will not be published. Required fields are marked *