In This Article
1. Classes in Python
Classes are a core mechanism of OOP. A class is a blueprint for creating objects with attributes (data) and methods (functions). Objects created from a class are called instances. Classes help structure code, improve reusability, and simplify maintenance.
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
- Instance Methods β operate on objects (
self). - Class Methods β operate on the class itself (
cls) with@classmethod. - 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()