Перейти до вмісту
> 💻 🧠 Код 1001 > 📚 > 🐍 Python >

  • від

Ось фінальна версія статті українською, з інтегрованим кодом у кінці.


Класи в Python, ООП та контекстні менеджери: повний посібник

Цей посібник охоплює об’єктно-орієнтоване програмування (ООП) у Python та контекстні менеджери, включно з практичними прикладами перехоплення stdout/stderr і використанням шаблону Tee для одночасного відображення та збереження виводу.


1. Класи в Python

Класи є центральним механізмом ООП. Клас — це шаблон для створення об’єктів з атрибутами (дані) та методами (функції). Об’єкти, створені на основі класу, називаються екземплярами (instances). Класи допомагають структурувати код, підвищувати повторне використання та спрощувати підтримку.

Структура класу

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

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

Ключові моменти:

  • __init__: конструктор для ініціалізації атрибутів об’єкта.
  • self: посилання на поточний екземпляр.
  • Атрибути: визначаються через self і доступні у всіх методах.
  • Методи: працюють з даними об’єкта.

Створення об’єктів

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())  # Вивід: 2020 Toyota Corolla

Типи методів

  1. Методи екземпляра — працюють на об’єктах (self).
  2. Методи класу — працюють на класі (cls) через @classmethod.
  3. Статичні методи — не залежать від екземпляра чи класу (@staticmethod).

Наслідування

class Animal:
    def speak(self):
        return 'Голос тварини'

class Dog(Animal):
    def speak(self):
        return 'Гав'

Поліморфізм

class Cat(Animal):
    def speak(self):
        return 'Мяу'

cat = Cat()
print(cat.speak())  # Вивід: Мяу
  • Та сама назва методу може працювати по-різному залежно від типу об’єкта.

Інкапсуляція

class Car:
    def __init__(self, make, model):
        self._make = make  # Захищений атрибут
        self._model = model

    def get_make(self):
        return self._make

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

Магічні методи та деструктор

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)  # Вивід: Point(3, 4)

ASCII-діаграма: наслідування та поліморфізм

       ┌─────────┐
       │ Animal  │
       └─────────┘
       │ speak() │
       └─────────┘
            ▲
    ┌───────┴────────┐
    │                │
┌─────────┐      ┌─────────┐
│  Dog    │      │  Cat    │
└─────────┘      └─────────┘
│ speak() │      │ speak() │
└─────────┘      └─────────┘

2. Контекстні менеджери в Python

Контекстні менеджери дозволяють автоматично виділяти та звільняти ресурси, навіть у разі помилок.

Використання @contextmanager

from contextlib import contextmanager

@contextmanager
def my_context():
    print("Вхід у контекст")
    try:
        yield "Ресурс"
    finally:
        print("Вихід з контексту")

Використання:

with my_context() as res:
    print("У контексті:", res)

Перехоплення stdout/stderr і Tee

Python дозволяє перехоплювати stdout, stderr або обидва, а також одночасно відображати та перехоплювати з допомогою шаблону Tee.


3. Повний приклад: oop_and_context.py


"""
oop_and_context.py

Приклади класів, принципів OOP і контекстних менеджерів у Python.
Містить:
- Визначення класів, наслідування, поліморфізм, інкапсуляцію
- Методи екземпляра, класу та статичні
- Магічні методи та деструктор
- Контекстні менеджери з @contextmanager
- Перехоплення stdout, stderr і обох одночасно
- Шаблон Tee: відображення та перехоплення одночасно
- Контекстний менеджер на основі класу
"""

import sys
import io
from contextlib import contextmanager

# ==========================
# Частина 1: Класи та OOP
# ==========================

class Animal:
    """Базовий клас для тварин."""
    def speak(self):
        return 'Голос тварини'

class Dog(Animal):
    def speak(self):
        return 'Гав'

class Cat(Animal):
    def speak(self):
        return 'Мяу'

class Car:
    """Приклад інкапсуляції."""
    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:
    """Клас з магічними методами."""
    def __init__(self, x, y):
        self.x = x
        self.y = y

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

# ==========================
# Частина 2: Контекстні менеджери
# ==========================

@contextmanager
def my_context():
    print("Вхід у контекст")
    try:
        yield "Ресурс"
    finally:
        print("Вихід з контексту")

@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):
    """Відображення та перехоплення одночасно."""
    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

# ==========================
# Частина 3: Контекстний менеджер на основі класу
# ==========================

class OutputCapture:
    """Контекстний менеджер на основі класу для перехоплення 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  # передати виключення далі

# ==========================
# Частина 4: Демонстрації
# ==========================

def demo_classes():
    print("\n--- Демонстрація класів ---")
    dog = Dog()
    cat = Cat()
    print("Собака каже:", dog.speak())
    print("Кіт каже:", cat.speak())

    my_car = Car('Toyota', 'Corolla', 2020)
    print("Опис авто:", my_car.description())
    my_car.set_make('Honda')
    print("Оновлений бренд:", my_car.get_make())

    point = Point(3, 4)
    print("Точка:", point)

def demo_context_managers():
    print("\n--- Демонстрація контекстних менеджерів ---")

    with my_context() as res:
        print("У контексті:", res)

    with capture_stdout() as out:
        print("stdout перехоплено")
    print("Буфер:", out.getvalue().strip())

    with capture_stderr() as err:
        print("Йде у stdout")
        sys.stderr.write("Повідомлення про помилку\n")
    print("Помилка:", err.getvalue().strip())

    with capture_output() as out_all:
        print("stdout у комбінованому перехопленні")
        sys.stderr.write("stderr у комбінованому перехопленні\n")
    print("Комбінований вивід:", out_all.getvalue().strip())

    with capture_stdout_tee() as tee_out:
        print("Вивід видимий І перехоплений (Tee)")
    print("Буфер Tee:", tee_out.getvalue().strip())

    with OutputCapture() as class_capture:
        print("Перехоплення за допомогою класового менеджера")
    print("Буфер класового менеджера:", class_capture.getvalue().strip())

# ==========================
# Основний запуск
# ==========================

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

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *