Стратегия (Strategy)
Стратегия — это поведенческий паттерн, который определяет семейство алгоритмов, инкапсулирует каждый из них и делает их взаимозаменяемыми. Стратегия позволяет изменять алгоритмы независимо от клиентов, которые ими пользуются.
class PaymentStrategy:
def pay(self, amount): pass
class CreditCardPayment(PaymentStrategy):
def pay(self, amount):
return f"Оплата {amount} картой"
class ShoppingCart:
def __init__(self):
self.payment_strategy = None
def checkout(self, amount):
return self.payment_strategy.pay(amount)
cart = ShoppingCart()
cart.payment_strategy = CreditCardPayment()
print(cart.checkout(1000)) # Оплата 1000 картой
👍2👏1
Адаптер (Adapter)
Адаптер — это структурный паттерн, который позволяет объектам с несовместимыми интерфейсами работать вместе. Адаптер выступает прослойкой между двумя объектами, превращая вызовы одного в вызовы понятные другому.
from abc import ABC, abstractmethod
class DataProcessor(ABC):
@abstractmethod
def process(self, data): pass
class XMLProcessor:
def process_xml(self, xml_data):
return f"Обработка XML: {xml_data}"
class XMLAdapter(DataProcessor):
def __init__(self, xml_processor):
self.xml_processor = xml_processor
def process(self, data):
xml_data = f"<data>{data}</data>"
return self.xml_processor.process_xml(xml_data)
# Использование
xml_processor = XMLProcessor()
adapter = XMLAdapter(xml_processor)
print(adapter.process("John")) # Обработка XML: <data>John</data>
👍3🔥1
Декоратор (Decorator)
Декоратор — это структурный паттерн, который позволяет динамически добавлять объектам новую функциональность, оборачивая их в полезные «обёртки». Декоратор предоставляет гибкую альтернативу наследованию для расширения функциональности.
class Coffee:
def cost(self): return 2.0
def desc(self): return "Кофе"
class MilkDecorator:
def __init__(self, coffee):
self.coffee = coffee
def cost(self): return self.coffee.cost() + 0.5
def desc(self): return self.coffee.desc() + " + молоко"
class SugarDecorator:
def __init__(self, coffee):
self.coffee = coffee
def cost(self): return self.coffee.cost() + 0.3
def desc(self): return self.coffee.desc() + " + сахар"
# Использование
coffee = SugarDecorator(MilkDecorator(Coffee()))
print(f"{coffee.desc()} = {coffee.cost()} руб.")
# Кофе + молоко + сахар = 2.8 руб
👍4🔥1
Создание пользовательских исключений
Пользовательские исключения делают код более читаемым и позволяют точно идентифицировать ошибки вашего приложения, отличая их от стандартных исключений Python.
Базовый пользовательский класс исключения:
class BankError(Exception):
pass
class InsufficientFundsError(BankError):
def __init__(self, balance, amount):
super().__init__(f"Баланс {balance}, нужно {amount}")
class Account:
def __init__(self, balance=0):
self.balance = balance
def withdraw(self, amount):
if amount > self.balance:
raise InsufficientFundsError(self.balance, amount)
self.balance -= amount
# Использование
acc = Account(100)
try:
acc.withdraw(200)
except InsufficientFundsError as e:
print(f"Ошибка: {e}") # Баланс 100, нужно 200
👍2
Наследование от встроенных исключений
Правильное наследование исключений:
В Python все исключения наследуются от базового класса Exception. При создании пользовательских исключений важно правильно выбрать родительский класс для совместимости.
class ValidationError(ValueError):
"""Наследуем от ValueError для совместимости"""
pass
def validate_age(age):
if age < 0:
raise ValidationError("Возраст не может быть отрицательным")
try:
validate_age(-5)
except ValueError as e: # ✅ Поймает ValidationError
print(f"Ошибка: {e}")
👍2
Обработка исключений в методах
Два подхода:
1. Обработка внутри метода
2. Проброс исключения наружу
Пример:
class FileReader:
def read_safe(self, filename):
"""Обработка внутри метода"""
try:
with open(filename) as f:
return f.read()
except FileNotFoundError:
return "" # Возвращаем значение по умолчанию
def read_strict(self, filename):
"""Проброс исключения наружу"""
with open(filename) as f:
return f.read() # FileNotFoundError пройдет выше
reader = FileReader()
content = reader.read_safe("нет_файла.txt") # Вернет ""
# reader.read_strict("нет_файла.txt") # Вызовет FileNotFoundError
👍1👏1
Контекстные менеджеры с классами
Классы с enter и exit:
Позволяют создавать свои контекстные менеджеры.
Пример:
class Timer:
"""Измеряет время выполнения блока кода"""
def __enter__(self):
import time
self.start = time.time()
def __exit__(self, *args):
import time
print(f"Выполнено за: {time.time() - self.start:.2f} сек.")
with Timer():
import time
time.sleep(1) # Вывод: Выполнено за: 1.00 сек.
👍2
Паттерн "Фабрика исключений"
Централизованное создание исключений:
Упрощает управление ошибками в больших проектах.
Пример:
class ExceptionFactory:
"""Создает стандартизированные исключения"""
@staticmethod
def validation_error(field, message):
return ValueError(f"[VALIDATION] {field}: {message}")
@staticmethod
def business_error(code, message):
error = RuntimeError(message)
error.code = code
return error
# Использование
try:
raise ExceptionFactory.validation_error("email", "Неверный формат")
except ValueError as e:
print(f"Ошибка: {e}") # [VALIDATION] email: Неверный формат
👍2
Модуль unittest для тестирования классов
Базовое тестирование:
Unittest — встроенный модуль для тестирования.
Пример:
import unittest
class Calculator:
def add(self, a, b):
return a + b
class TestCalculator(unittest.TestCase):
def setUp(self):
"""Подготовка перед каждым тестом"""
self.calc = Calculator()
def test_add_positive(self):
self.assertEqual(self.calc.add(2, 3), 5)
def test_add_negative(self):
self.assertEqual(self.calc.add(-1, -1), -2)
if __name__ == "__main__":
unittest.main()
👍2
Mock объекты для тестирования
Изоляция зависимостей:
Mock-объекты имитируют реальные объекты для тестирования.
Пример:
from unittest.mock import Mock
class WeatherService:
def __init__(self, api):
self.api = api
def get_temp(self, city):
return self.api.fetch(city)['temp']
# Тест
mock_api = Mock()
mock_api.fetch.return_value = {'temp': 25}
service = WeatherService(mock_api)
result = service.get_temp("Москва")
assert result == 25
mock_api.fetch.assert_called_once_with("Москва")
👍1👏1
Тестирование наследования
Проверка полиморфного поведения:
Тестируем, что дочерние классы правильно переопределяют методы.
Пример:
class Animal:
def speak(self):
return "Звук"
class Dog(Animal):
def speak(self):
return "Гав"
class TestAnimals(unittest.TestCase):
def test_inheritance(self):
dog = Dog()
self.assertEqual(dog.speak(), "Гав")
self.assertIsInstance(dog, Animal)
👍1👏1
Тестирование приватных методов
Лучше тестировать через публичный интерфейс:
Но иногда нужен прямой доступ.
Пример:
class Validator:
def _validate_email(self, email):
return "@" in email
def register_user(self, email):
if not self._validate_email(email):
raise ValueError("Неверный email")
return True
# Тестируем через публичный метод
validator = Validator()
self.assertTrue(validator.register_user("test@mail.com"))
with self.assertRaises(ValueError):
validator.register_user("invalid-email")
👍2
Паттерн "Тестовые дублеры"
Разные типы дублеров:
Mock, Stub, Fake, Spy для разных задач.
Пример:
from unittest.mock import Mock
class Database:
def get_user(self, user_id):
# Реальный код работы с БД
pass
class UserService:
def __init__(self, db):
self.db = db
def get_user_name(self, user_id):
user = self.db.get_user(user_id)
return user['name'] if user else None
# Используем Mock как тестовый дублер
mock_db = Mock()
mock_db.get_user.return_value = {'name': 'Анна', 'id': 1}
service = UserService(mock_db)
assert service.get_user_name(1) == 'Анна'
👍1🔥1
Дескрипторы
Управление доступом к атрибутам:
Дескрипторы контролируют, как устанавливаются и получаются значения атрибутов.
Пример:
class PositiveNumber:
"""Дескриптор для положительных чисел"""
def __set__(self, obj, value):
if value < 0:
raise ValueError("Число должно быть положительным")
obj.__dict__[self.name] = value
def __set_name__(self, owner, name):
self.name = name
class Account:
balance = PositiveNumber()
def __init__(self, balance):
self.balance = balance # Вызовет __set__
acc = Account(100) # OK
# acc.balance = -50 # ValueError: Число должно быть положительным
👍2
Слоты slots
Оптимизация памяти:
Ограничивает набор атрибутов и экономит память.
Пример:
class Point:
__slots__ = ['x', 'y'] # Только эти атрибуты разрешены
def __init__(self, x, y):
self.x = x
self.y = y
p = Point(1, 2)
print(p.x, p.y) # 1 2
# p.z = 3 # AttributeError: 'Point' object has no attribute 'z'
👍3
Абстрактные методы
Принудительная реализация:
Абстрактные методы должны быть реализованы в дочерних классах.
Пример:
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
"""Должен быть реализован в дочерних классах"""
pass
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self): # Обязательная реализация
return 3.14 * self.radius ** 2
# Shape() # TypeError: нельзя создать экземпляр абстрактного класса
circle = Circle(5) # OK
print(circle.area()) # 78.5
👍2
Протоколы и интерфейсы
Неявные интерфейсы Python:
Если объект имеет нужные методы, он соответствует протоколу.
Пример:
from typing import Protocol
class Drawable(Protocol):
def draw(self) -> str: ...
class Circle:
def draw(self):
return "Рисую круг"
class Square:
def draw(self):
return "Рисую квадрат"
def render(obj: Drawable):
return obj.draw()
print(render(Circle())) # "Рисую круг"
print(render(Square())) # "Рисую квадрат"
👍3
Миксины (Mixins)
Множественное наследование для функциональности:
Миксины добавляют возможности без изменения основной логики.
Пример:
class JSONSerializable:
"""Миксин для сериализации в JSON"""
def to_json(self):
import json
return json.dumps(self.__dict__)
class Timestamped:
"""Миксин для добавления временных меток"""
def __init__(self):
from datetime import datetime
self.created_at = datetime.now()
class User(Timestamped, JSONSerializable):
"""Класс пользователя с миксинами"""
def __init__(self, name, email):
super().__init__() # Вызываем __init__ миксинов
self.name = name
self.email = email
user = User("Анна", "anna@example.com")
print(user.to_json()) # JSON с created_at, name, email
👍4
С Новым 2026 годом! Пусть этот год принесет вам радость, счастье и исполнение всех заветных желаний. Пусть каждый день будет наполнен яркими моментами, новыми достижениями и приятными сюрпризами.
@SV_Python
@SV_Python
🎄5🔥1🤩1
