Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Примеры ООП в Python
Объектно-ориентированное программирование (ООП) — это парадигма, которая организует код вокруг объектов, имеющих состояние (атрибуты) и поведение (методы). Рассмотрим примеры от базовых до продвинутых.
1. Основные концепции
Класс и объект
# Класс - это шаблон
class Car:
# Атрибут класса (общий для всех объектов)
wheels = 4
# Конструктор - вызывается при создании объекта
def __init__(self, brand: str, model: str, speed: float):
# Атрибуты объекта (индивидуальные)
self.brand = brand
self.model = model
self.speed = speed
self.is_running = False
# Методы
def start(self):
"""Запустить автомобиль"""
self.is_running = True
print(f"{self.brand} {self.model} запущен")
def stop(self):
"""Остановить автомобиль"""
self.is_running = False
print(f"{self.brand} {self.model} остановлен")
def drive(self, distance: float):
"""Ехать на определённое расстояние"""
if not self.is_running:
print(f"Сначала запустите автомобиль")
return
time_required = distance / self.speed
print(f"Проехали {distance}км за {time_required:.1f} часов")
# Создаём объекты (экземпляры класса)
car1 = Car("Toyota", "Camry", 180)
car2 = Car("BMW", "X5", 220)
# Используем объекты
car1.start()
car1.drive(100)
car1.stop()
print(f"Количество колес: {car1.wheels}")
print(f"Количество колес: {car2.wheels}")
2. Наследование (Inheritance)
Наследование позволяет создавать новые классы на основе существующих.
# Базовый класс (родитель)
class Vehicle:
def __init__(self, brand: str):
self.brand = brand
self.is_running = False
def start(self):
self.is_running = True
print(f"{self.brand} запущен")
def stop(self):
self.is_running = False
print(f"{self.brand} остановлен")
# Класс-наследник (потомок)
class Car(Vehicle):
def __init__(self, brand: str, model: str, num_doors: int):
# Вызываем конструктор родителя
super().__init__(brand)
self.model = model
self.num_doors = num_doors
# Переопределяем (override) метод родителя
def start(self):
super().start() # Вызываем метод родителя
print(f"Двигатель {self.model} прогревается")
# Новый метод, уникальный для Car
def open_trunk(self):
print(f"Открыли багажник {self.model}")
# Ещё один наследник
class Motorcycle(Vehicle):
def __init__(self, brand: str, has_sidecar: bool):
super().__init__(brand)
self.has_sidecar = has_sidecar
def wheelie(self):
if not self.is_running:
print("Запустите мотоцикл!")
return
print(f"{self.brand} встал на заднее колесо!")
# Использование
car = Car("Toyota", "Camry", 4)
car.start()
car.open_trunk()
car.stop()
moto = Motorcycle("Harley", False)
moto.start()
moto.wheelie()
moto.stop()
3. Инкапсуляция (Encapsulation)
Скрывание деталей реализации и предоставление контролируемого доступа.
class BankAccount:
def __init__(self, owner: str, balance: float):
self.owner = owner
# Private атрибут (по соглашению, начинается с _)
self._balance = balance
# Очень private (name mangling)
self.__pin = "1234"
# Public метод
def deposit(self, amount: float):
"""Пополнить счёт"""
if amount > 0:
self._balance += amount
print(f"Пополнено на {amount}. Новый баланс: {self._balance}")
else:
print("Сумма должна быть больше нуля")
# Public метод с проверкой
def withdraw(self, amount: float, pin: str):
"""Снять деньги со счёта"""
if not self._verify_pin(pin):
print("Неверный PIN")
return
if amount > self._balance:
print("Недостаточно средств")
return
self._balance -= amount
print(f"Снято {amount}. Остаток: {self._balance}")
# Property - управляемый доступ к атрибутам
@property
def balance(self):
"""Получить баланс (читать можно, менять нельзя)"""
return self._balance
# Private метод
def _verify_pin(self, pin: str) -> bool:
"""Проверить PIN (не вызывается снаружи)"""
return pin == self.__pin
def __str__(self):
return f"Счёт {self.owner}: {self._balance} руб"
# Использование
account = BankAccount("John", 10000)
print(account) # Счёт John: 10000 руб
account.deposit(5000)
account.withdraw(3000, "1234")
# Это работает
print(account.balance) # 12000
# Это НЕ работает (по соглашению)
# account._balance = 1000000 # НЕ ДЕЛАЙТЕ ТАК!
4. Полиморфизм (Polymorphism)
Один интерфейс, разные реализации.
# Базовый класс
class Animal:
def speak(self):
pass
def move(self):
pass
# Разные реализации
class Dog(Animal):
def speak(self):
return "Гав! Гав!"
def move(self):
return "Бежит на четырёх лапах"
class Cat(Animal):
def speak(self):
return "Мяу"
def move(self):
return "Прыгает и ходит изящно"
class Duck(Animal):
def speak(self):
return "Кря-кря"
def move(self):
return "Плывёт в воде"
# Полиморфизм в действии
def animal_concert(animals: list):
for animal in animals:
print(f"{animal.__class__.__name__}: {animal.speak()}")
print(f"{animal.__class__.__name__}: {animal.move()}")
print()
# Один код, разные объекты
animals = [Dog(), Cat(), Duck()]
animal_concert(animals)
# Вывод:
# Dog: Гав! Гав!
# Dog: Бежит на четырёх лапах
#
# Cat: Мяу
# Cat: Прыгает и ходит изящно
# ...
5. Абстрактные классы (Abstract Classes)
Классы, которые нельзя инстанцировать, они только для наследования.
from abc import ABC, abstractmethod
# Абстрактный класс
class Shape(ABC):
@abstractmethod
def area(self) -> float:
"""Вычислить площадь (должен быть реализован в подклассах)"""
pass
@abstractmethod
def perimeter(self) -> float:
"""Вычислить периметр"""
pass
# Обычный метод в абстрактном классе
def describe(self):
print(f"{self.__class__.__name__}: S={self.area():.1f}, P={self.perimeter():.1f}")
# Реализации
class Circle(Shape):
def __init__(self, radius: float):
self.radius = radius
def area(self) -> float:
return 3.14 * self.radius ** 2
def perimeter(self) -> float:
return 2 * 3.14 * self.radius
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 perimeter(self) -> float:
return 2 * (self.width + self.height)
# Использование
shapes = [Circle(5), Rectangle(4, 6)]
for shape in shapes:
shape.describe()
# Это НЕ работает - абстрактный класс нельзя инстанцировать
# shape = Shape() # TypeError: Can't instantiate abstract class
6. Множественное наследование
class Flyer:
def fly(self):
return "Летит в небе"
class Swimmer:
def swim(self):
return "Плывёт в воде"
class Walker:
def walk(self):
return "Ходит по земле"
# Один класс наследует от нескольких
class Duck(Flyer, Swimmer, Walker):
def quack(self):
return "Кря-кря"
# MRO - Method Resolution Order (порядок поиска методов)
print(Duck.__mro__) # Порядок поиска методов
duck = Duck()
print(duck.fly()) # Летит в небе
print(duck.swim()) # Плывёт в воде
print(duck.walk()) # Ходит по земле
print(duck.quack()) # Кря-кря
7. Композиция (Composition)
Использование объектов других классов внутри класса.
class Engine:
def __init__(self, power: int):
self.power = power
def start(self):
return f"Двигатель {self.power}л запущен"
class Wheel:
def __init__(self, size: int):
self.size = size
def rotate(self):
return f"Колесо {self.size}' вращается"
class Car:
def __init__(self, brand: str, engine: Engine):
self.brand = brand
self.engine = engine
self.wheels = [Wheel(18) for _ in range(4)]
def start(self):
print(self.engine.start())
for i, wheel in enumerate(self.wheels):
print(f"Колесо {i+1}: {wheel.rotate()}")
# Использование
engine = Engine(3)
car = Car("BMW", engine)
car.start()
# Композиция предпочтительнее наследования в Python:
# "Composition over Inheritance"
8. Magic Methods (Дандер методы)
class Vector:
def __init__(self, x: float, y: float):
self.x = x
self.y = y
# Строковое представление
def __str__(self):
return f"Vector({self.x}, {self.y})"
# Для разработчиков (более полная информация)
def __repr__(self):
return f"Vector(x={self.x}, y={self.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 __eq__(self, other):
return self.x == other.x and self.y == other.y
# Длина вектора
def __len__(self):
return int((self.x**2 + self.y**2)**0.5)
# Хешируемость
def __hash__(self):
return hash((self.x, self.y))
# Использование
v1 = Vector(3, 4)
v2 = Vector(1, 2)
print(v1) # Vector(3, 4)
print(v1 + v2) # Vector(4, 6)
print(v1 - v2) # Vector(2, 2)
print(v1 * 2) # Vector(6, 8)
print(v1 == v2) # False
print(len(v1)) # 5 (гипотенуза)
# Использование как ключ словаря
positions = {v1: "point1", v2: "point2"}
9. Декораторы класса
from dataclasses import dataclass
from typing import List
# Автоматически генерирует __init__, __repr__, __eq__ и т.д.
@dataclass
class User:
id: int
name: str
email: str
tags: List[str] = None # Со значением по умолчанию
def __post_init__(self):
if self.tags is None:
self.tags = []
# Использование
user1 = User(1, "John", "john@example.com")
user2 = User(1, "John", "john@example.com")
print(user1) # User(id=1, name='John', email='john@example.com', tags=[])
print(user1 == user2) # True (автоматическое сравнение)
10. Контекстные менеджеры (Context Managers)
class DatabaseConnection:
def __init__(self, host: str):
self.host = host
self.connected = False
def __enter__(self): # Вход в контекст (with ...)
print(f"Подключение к {self.host}...")
self.connected = True
return self
def __exit__(self, exc_type, exc_val, exc_tb): # Выход из контекста
print(f"Отключение от {self.host}")
self.connected = False
# Возвращаем True, чтобы подавить исключение
if exc_type:
print(f"Ошибка: {exc_val}")
return False
def query(self, sql: str):
if not self.connected:
raise RuntimeError("Не подключено")
return f"Результат: {sql}"
# Использование with (автоматический __enter__ и __exit__)
with DatabaseConnection("localhost") as db:
print(db.query("SELECT * FROM users"))
# Автоматически закрывается!
Best Practices в ООП
# ✅ Хорошее ООП
class GoodExample:
"""Один класс - одна ответственность"""
def __init__(self, name: str):
self._name = name
@property
def name(self) -> str:
return self._name
def do_something(self):
pass
# ❌ Плохое ООП
class BadExample:
"""Слишком много ответственности"""
def __init__(self):
self.users = []
self.products = []
self.orders = []
def add_user(self): pass
def remove_user(self): pass
def add_product(self): pass
def remove_product(self): pass
def create_order(self): pass
def process_payment(self): pass
def send_email(self): pass
# и 20 других методов...
Заключение
ООП в Python позволяет:
- Организовать код вокруг сущностей предметной области
- Переиспользовать код через наследование и композицию
- Скрывать деталями реализации через инкапсуляцию
- Создавать гибкий код через полиморфизм
- Писать чистый код следуя SOLID принципам
Железное правило: Используй ООП когда это упрощает код, а не когда усложняет. Python поддерживает разные парадигмы - используй то, что подходит к задаче.