← Назад к вопросам

Для каких задач лучше использовать класс в Python

2.0 Middle🔥 121 комментариев
#Python Core#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Когда использовать классы в Python

Классы — фундаментальная часть объектно-ориентированного программирования. Правильный выбор между функциями и классами критичен для чистоты и поддерживаемости кода.

1. Когда нужен класс

Когда нужно сохранять состояние (данные):

# Плохо: функции с глобальным состоянием
user_name = None
user_email = None
user_age = None

def set_user(name, email, age):
    global user_name, user_email, user_age
    user_name = name
    user_email = email
    user_age = age

def get_user_info():
    return f"{user_name} ({user_email})"

# Хорошо: класс для инкапсуляции состояния
class User:
    def __init__(self, name, email, age):
        self.name = name
        self.email = email
        self.age = age
    
    def get_info(self):
        return f"{self.name} ({self.email})"

user = User("John", "john@example.com", 30)
print(user.get_info())

Когда нужно несколько экземпляров одного типа:

class Product:
    def __init__(self, name, price, stock):
        self.name = name
        self.price = price
        self.stock = stock
    
    def apply_discount(self, discount_percent):
        self.price *= (1 - discount_percent / 100)
        return self.price

# Создаём множество объектов
products = [
    Product("Laptop", 1000, 5),
    Product("Mouse", 25, 50),
    Product("Keyboard", 75, 30),
]

for product in products:
    new_price = product.apply_discount(10)
    print(f"{product.name}: {new_price}")

2. Модель данных с поведением

Класс объединяет данные и методы для их обработки:

class BankAccount:
    def __init__(self, owner, balance):
        self.owner = owner
        self._balance = balance  # приватный атрибут
    
    def deposit(self, amount):
        if amount > 0:
            self._balance += amount
            return True
        return False
    
    def withdraw(self, amount):
        if 0 < amount <= self._balance:
            self._balance -= amount
            return True
        return False
    
    def get_balance(self):
        return self._balance

# Использование
account = BankAccount("Alice", 1000)
account.deposit(500)
account.withdraw(200)
print(f"Баланс: {account.get_balance()}")  # 1300

3. Наследование и полиморфизм

Когда нужна иерархия типов:

class Animal:
    def __init__(self, name):
        self.name = name
    
    def speak(self):
        raise NotImplementedError("Подклассы должны реализовать speak()")

class Dog(Animal):
    def speak(self):
        return f"{self.name} говорит: Гав!"

class Cat(Animal):
    def speak(self):
        return f"{self.name} говорит: Мяу!"

# Полиморфизм
animals = [Dog("Шарик"), Cat("Мурка"), Dog("Барбос")]
for animal in animals:
    print(animal.speak())

4. Инкапсуляция и контроль доступа

Классы позволяют скрыть внутренние детали:

class Temperature:
    def __init__(self, celsius):
        self._celsius = celsius
    
    @property
    def celsius(self):
        return self._celsius
    
    @property
    def fahrenheit(self):
        return self._celsius * 9/5 + 32
    
    @celsius.setter
    def celsius(self, value):
        if value < -273.15:
            raise ValueError("Температура ниже абсолютного нуля")
        self._celsius = value

temp = Temperature(25)
print(temp.celsius)  # 25
print(temp.fahrenheit)  # 77
temp.celsius = 30  # Проверка через setter

5. Специальные методы (dunder methods)

Классы позволяют определить поведение операторов:

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)
    
    def __sub__(self, other):
        return Vector(self.x - other.x, self.y - other.y)
    
    def __mul__(self, scalar):
        return Vector(self.x * scalar, self.y * scalar)
    
    def __str__(self):
        return f"Vector({self.x}, {self.y})"
    
    def __repr__(self):
        return self.__str__()
    
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

v1 = Vector(1, 2)
v2 = Vector(3, 4)
v3 = v1 + v2
print(v3)  # Vector(4, 6)
print(v1 * 2)  # Vector(2, 4)
print(v1 == Vector(1, 2))  # True

6. Контекстные менеджеры

Классы с __enter__ и __exit__ для управления ресурсами:

class DatabaseConnection:
    def __init__(self, connection_string):
        self.connection_string = connection_string
        self.connection = None
    
    def __enter__(self):
        print(f"Подключаюсь к {self.connection_string}")
        self.connection = "<фиксированное соединение>"
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Закрываю соединение")
        self.connection = None
        return False
    
    def query(self, sql):
        if self.connection:
            print(f"Выполняю: {sql}")
        return "Результат"

with DatabaseConnection("postgresql://localhost") as db:
    result = db.query("SELECT * FROM users")
    print(result)

7. Когда НЕ нужен класс

Если нужна только одна функция — используй функцию:

# Плохо: класс для простого преобразования
class Converter:
    @staticmethod
    def celsius_to_fahrenheit(celsius):
        return celsius * 9/5 + 32

# Хорошо: просто функция
def celsius_to_fahrenheit(celsius):
    return celsius * 9/5 + 32

result = celsius_to_fahrenheit(25)

Если только нужны статические методы:

# Плохо: класс с только статическими методами
class Math:
    @staticmethod
    def add(a, b):
        return a + b
    
    @staticmethod
    def multiply(a, b):
        return a * b

# Хорошо: просто функции в модуле
def add(a, b):
    return a + b

def multiply(a, b):
    return a * b

8. Пример реальной задачи: система напоминаний

from datetime import datetime, timedelta
from enum import Enum

class ReminderType(Enum):
    ONCE = "once"
    DAILY = "daily"
    WEEKLY = "weekly"

class Reminder:
    def __init__(self, title, description, time, reminder_type):
        self.title = title
        self.description = description
        self.time = time
        self.reminder_type = reminder_type
        self.created_at = datetime.now()
        self.is_active = True
    
    def should_trigger(self):
        """Проверить, должно ли напоминание сработать"""
        if not self.is_active:
            return False
        
        current_time = datetime.now()
        
        if self.reminder_type == ReminderType.ONCE:
            return current_time >= self.time
        elif self.reminder_type == ReminderType.DAILY:
            return current_time.time() >= self.time.time()
        elif self.reminder_type == ReminderType.WEEKLY:
            return (current_time.weekday() == self.time.weekday() and 
                    current_time.time() >= self.time.time())
        
        return False
    
    def trigger(self):
        """Сработать напоминание"""
        print(f"УВЕДОМЛЕНИЕ: {self.title}")
        print(f"Описание: {self.description}")
        
        if self.reminder_type == ReminderType.ONCE:
            self.is_active = False
    
    def __str__(self):
        return f"Reminder: {self.title} @ {self.time}"

class ReminderService:
    def __init__(self):
        self.reminders = []
    
    def add_reminder(self, reminder):
        self.reminders.append(reminder)
    
    def check_all(self):
        """Проверить все напоминания"""
        for reminder in self.reminders:
            if reminder.should_trigger():
                reminder.trigger()
    
    def get_active_reminders(self):
        return [r for r in self.reminders if r.is_active]

# Использование
service = ReminderService()
service.add_reminder(Reminder(
    "Встреча",
    "Встреча с клиентом",
    datetime.now() + timedelta(hours=1),
    ReminderType.ONCE
))

service.check_all()

Заключение

Используй класс если:

  • Нужно сохранять состояние (данные)
  • Создаёшь несколько экземпляров
  • Нужна иерархия типов (наследование)
  • Нужна инкапсуляция
  • Нужны специальные методы (add, str, и т.д.)
  • Реализуешь контекстный менеджер

Используй функцию если:

  • Простое преобразование или вычисление
  • Нет состояния
  • Нет нескольких экземпляров
  • Нет связанного поведения