Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI21 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Классы в объектно-ориентированном программировании
Класс — это blueprint (чертёж) для создания объектов. Это шаблон, который определяет структуру (атрибуты) и поведение (методы) объектов определённого типа. Классы — основа ООП.
Базовая концепция
# Класс — это шаблон
class Dog:
# Атрибуты класса (shared всеми объектами)
species = "Canis familiaris"
# Конструктор — инициализирует объект
def __init__(self, name: str, age: int):
# Атрибуты экземпляра (уникальны для каждого объекта)
self.name = name
self.age = age
# Методы — поведение
def bark(self) -> str:
return f"{self.name} says Woof!"
def birthday(self) -> None:
self.age += 1
# Создание объектов (экземпляров класса)
dog1 = Dog("Rex", 5)
dog2 = Dog("Max", 3)
print(dog1.bark()) # Rex says Woof!
dog1.birthday()
print(dog1.age) # 6
Четыре столпа ООП
1. Инкапсуляция (Encapsulation)
Хранение данных и методов вместе, скрытие внутренней реализации.
class BankAccount:
def __init__(self, balance: float):
# Приватный атрибут (по соглашению _balance)
self._balance = balance
# Getter
@property
def balance(self) -> float:
return self._balance
# Setter с проверкой
@balance.setter
def balance(self, value: float) -> None:
if value < 0:
raise ValueError("Balance не может быть отрицательным")
self._balance = value
def withdraw(self, amount: float) -> None:
if amount > self._balance:
raise ValueError("Недостаточно средств")
self._balance -= amount
# Использование
account = BankAccount(1000)
print(account.balance) # 1000
account.withdraw(100)
print(account.balance) # 900
account.balance = -100 # ValueError!
Смысл: пользователь не может напрямую изменить balance, только через контролируемые методы.
2. Наследование (Inheritance)
Дочерний класс наследует свойства и методы родительского класса.
# Родительский класс (базовый)
class Animal:
def __init__(self, name: str):
self.name = name
def speak(self) -> str:
return f"{self.name} makes a sound"
# Дочерние классы наследуют от Animal
class Dog(Animal):
def speak(self) -> str:
return f"{self.name} says Woof!"
class Cat(Animal):
def speak(self) -> str:
return f"{self.name} says Meow!"
# Использование
dog = Dog("Rex")
cat = Cat("Whiskers")
print(dog.speak()) # Rex says Woof!
print(cat.speak()) # Whiskers says Meow!
# Оба имеют атрибут name от родителя
print(dog.name) # Rex
print(cat.name) # Whiskers
super() для вызова родительского класса:
class Dog(Animal):
def __init__(self, name: str, breed: str):
super().__init__(name) # Вызываем __init__ родителя
self.breed = breed
def speak(self) -> str:
parent_sound = super().speak() # Rex makes a sound
return f"{parent_sound}, specifically Woof!"
3. Полиморфизм (Polymorphism)
Одна и та же функция работает по-разному в зависимости от типа объекта.
class Shape:
def area(self) -> float:
raise NotImplementedError
class Circle(Shape):
def __init__(self, radius: float):
self.radius = radius
def area(self) -> float:
return 3.14 * self.radius ** 2
class Rectangle(Shape):
def __init__(self, width: float, height: float):
self.width = width
self.height = height
def area(self) -> float:
return self.width * self.height
# Полиморфизм — одна функция работает с разными типами
def print_area(shape: Shape) -> None:
print(f"Area: {shape.area()}")
circle = Circle(5)
rectangle = Rectangle(4, 6)
print_area(circle) # Area: 78.5
print_area(rectangle) # Area: 24
# Каждый класс реализует area() по-своему
4. Абстракция (Abstraction)
Скрытие сложности, предоставление простого интерфейса.
from abc import ABC, abstractmethod
# Абстрактный класс — не может быть создан напрямую
class PaymentProcessor(ABC):
@abstractmethod
def process_payment(self, amount: float) -> bool:
pass
@abstractmethod
def refund(self, transaction_id: str) -> bool:
pass
# Конкретные реализации
class StripeProcessor(PaymentProcessor):
def process_payment(self, amount: float) -> bool:
# Логика для Stripe
print(f"Processing ${amount} via Stripe")
return True
def refund(self, transaction_id: str) -> bool:
print(f"Refunding {transaction_id} via Stripe")
return True
class PayPalProcessor(PaymentProcessor):
def process_payment(self, amount: float) -> bool:
# Логика для PayPal
print(f"Processing ${amount} via PayPal")
return True
def refund(self, transaction_id: str) -> bool:
print(f"Refunding {transaction_id} via PayPal")
return True
# Использование
def checkout(processor: PaymentProcessor, amount: float):
# Не важно какой процессор, интерфейс одинаковый
processor.process_payment(amount)
stripe = StripeProcessor()
checkout(stripe, 99.99) # Processing $99.99 via Stripe
Полезные паттерны
Dataclass (для простых данных)
from dataclasses import dataclass
from datetime import datetime
@dataclass
class User:
id: int
name: str
email: str
created_at: datetime = datetime.now()
# Автоматически генерирует __init__, __repr__, __eq__
# Использование
user = User(1, "Alice", "alice@example.com")
print(user) # User(id=1, name='Alice', email='alice@example.com', ...)
Singleton паттерн (один экземпляр)
class Database:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
db1 = Database()
db2 = Database()
print(db1 is db2) # True — одинаковые объекты!
Composition вместо наследования
# Плохо — много наследования
class Dog(Animal, Domesticated, Furry):
pass
# Хорошо — композиция
class Dog:
def __init__(self, name: str):
self.name = name
self.fur = FurBehavior()
self.domestication = DomestificationBehavior()
def play(self):
self.fur.shed()
self.domestication.obey()
Методы специального назначения (dunder methods)
class Person:
def __init__(self, name: str, age: int):
self.name = name
self.age = age
def __str__(self) -> str:
"""Читаемое представление"""
return f"{self.name} ({self.age} years old)"
def __repr__(self) -> str:
"""Для разработчиков"""
return f"Person(name='{self.name}', age={self.age})"
def __eq__(self, other) -> bool:
"""Сравнение"""
return self.name == other.name and self.age == other.age
def __lt__(self, other) -> bool:
"""Сортировка"""
return self.age < other.age
def __len__(self) -> int:
"""Длина строки имени"""
return len(self.name)
def __call__(self) -> str:
"""Вызовимый объект"""
return f"Calling {self.name}"
person = Person("Alice", 30)
print(str(person)) # Alice (30 years old)
print(repr(person)) # Person(name='Alice', age=30)
print(len(person)) # 5
print(person()) # Calling Alice
Важные моменты
- Класс vs объект: Класс — это шаблон, объект — экземпляр класса
- self: Первый параметр метода — ссылка на сам объект
- init: Конструктор, вызывается при создании объекта
- Приватность: _ (одиночный underscore) — соглашение о приватности, не закон
- Type hints: Используй для ясности
- Наследование: Используй для код-переиспользования, но предпочитай композицию
Классы — мощный инструмент для организации кода, но помни о SOLID принципах и избегай over-engineering.