ООП в Python: 10 практических заданий для роста от новичка к pro
Для кого эта статья:
- Студенты и новички в программировании, интересующиеся Python и объектно-ориентированным программированием
- Разработчики, желающие улучшить свои навыки в ООП и перейти на более высокий уровень программирования
Инструкторы и преподаватели, ищущие практические материалы для обучения ООП на Python
Объектно-ориентированное программирование в Python — это мощный инструмент, который трансформирует код из хаотичного набора инструкций в организованную структуру. Многие разработчики застревают на теоретическом понимании ООП, не применяя его на практике. А ведь именно практические задания по ООП на Python раскрывают истинную силу этой парадигмы. Опыт показывает: программист, освоивший ООП до уровня автоматизма, решает сложные задачи в 3-4 раза быстрее коллег, работающих в процедурном стиле. Готовы преобразить свой подход к программированию? 🚀
Ищете структурированный путь к мастерству в Python? Обучение Python-разработке от Skypro — это не просто теория, а практический подход к ООП с реальными проектами. Наши студенты создают полноценные приложения уже к середине курса, применяя принципы ООП на конкретных задачах. Вместо туманных концепций — чёткая система, превращающая новичка в профессионала за 9 месяцев. Присоединяйтесь!
Концепция ООП в Python: основные практические задания
Объектно-ориентированное программирование — это не теоретическая концепция, а практический инструмент. В Python ООП реализуется элегантно и интуитивно, но без практики эти знания остаются лишь абстракцией. Ключевые концепции ООП — инкапсуляция, наследование и полиморфизм — требуют регулярных упражнений для их полного усвоения.
Михаил Светлов, технический директор образовательной платформы:
Однажды я столкнулся с задачей обучения команды джуниор-разработчиков основам ООП. Классические лекции давали минимальный эффект — студенты кивали, но код писали процедурно. Тогда я разработал серию практических заданий, начиная с создания простейшего класса "Книга" с методами для учёта страниц и оценки скорости чтения. Через неделю практики 80% команды начали самостоятельно проектировать небольшие системы классов, а через месяц мы успешно внедрили компонентную архитектуру в проект. Ключом стала именно регулярная практика с постепенным усложнением заданий.
Давайте начнем с базовых практических заданий, которые помогут освоить фундаментальные концепции ООП в Python:
| Задание | Концепция ООП | Уровень сложности | Ключевые навыки |
|---|---|---|---|
| Создание класса "Калькулятор" с базовыми арифметическими операциями | Инкапсуляция | Начальный | Определение методов, создание объектов |
| Разработка системы учета библиотеки с классами "Книга", "Автор", "Читатель" | Композиция | Начальный+ | Связи между объектами, атрибуты класса |
| Создание класса для парсинга CSV-файлов с возможностью фильтрации | Инкапсуляция, итераторы | Средний | Специальные методы, работа с файлами |
Основное практическое задание для новичков: создайте класс BankAccount, который будет отслеживать баланс счета, позволять вносить и снимать средства, а также предоставлять информацию о транзакциях. 💰
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner
self.balance = balance
self.transactions = []
def deposit(self, amount):
self.balance += amount
self.transactions.append(f"Внесено: {amount}")
return self.balance
def withdraw(self, amount):
if amount > self.balance:
return "Недостаточно средств"
self.balance -= amount
self.transactions.append(f"Снято: {amount}")
return self.balance
def get_balance(self):
return f"Баланс счета {self.owner}: {self.balance}"
def get_transactions(self):
return self.transactions
Практические задания с этим классом:
- Создайте несколько экземпляров класса для разных владельцев
- Реализуйте метод перевода средств между счетами
- Добавьте функционал начисления процентов по счету
- Расширьте класс системой уведомлений о крупных транзакциях
Эти упражнения закладывают фундамент понимания объектно-ориентированного подхода, заставляя мыслить в категориях объектов и их взаимодействий, а не последовательностей операций. 🧠

Классы и объекты: базовые практические упражнения
Классы и объекты — фундамент объектно-ориентированного программирования. Практические задания по ООП на Python должны начинаться именно с них. Понимание того, как создавать классы, инициализировать объекты и использовать их методы — первый шаг к мастерству ООП.
Рассмотрим несколько базовых практических упражнений, которые помогут укрепить понимание классов и объектов в Python:
Упражнение 1: Класс "Товар"
Создайте класс Product, который содержит информацию о товаре: название, цена, количество на складе. Реализуйте методы для изменения количества и получения общей стоимости товаров.
class Product:
def __init__(self, name, price, quantity):
self.name = name
self.price = price
self.quantity = quantity
def update_quantity(self, new_quantity):
self.quantity = new_quantity
return self.quantity
def calculate_total(self):
return self.price * self.quantity
def product_info(self):
return f"{self.name}: ${self.price}, in stock: {self.quantity}"
Задачи для практики:
- Создайте несколько товаров и рассчитайте общую стоимость инвентаря
- Добавьте метод для применения скидки к товару
- Реализуйте функцию поиска самого дорогого товара из списка объектов Product
Упражнение 2: Класс "Геометрическая фигура"
Создайте класс Shape с методами для расчета площади и периметра. Затем реализуйте несколько конкретных фигур.
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
def perimeter(self):
return 2 * (self.width + self.height)
def scale(self, factor):
self.width *= factor
self.height *= factor
Задачи для практики:
- Создайте классы для других геометрических фигур (круг, треугольник)
- Реализуйте метод, который проверяет, может ли одна фигура поместиться внутри другой
- Добавьте функционал для масштабирования фигуры
Упражнение 3: Класс "Студент"
Разработайте класс Student, который хранит информацию о студенте: имя, список курсов и оценки. Реализуйте методы для расчета среднего балла и добавления новых курсов.
class Student:
def __init__(self, name):
self.name = name
self.courses = {} # курс: оценка
def add_course(self, course, grade=None):
self.courses[course] = grade
def average_grade(self):
grades = [g for g in self.courses.values() if g is not None]
return sum(grades) / len(grades) if grades else 0
def complete_course(self, course, grade):
if course in self.courses:
self.courses[course] = grade
Практические задачи для этого класса:
- Создайте группу студентов и найдите студента с лучшей успеваемостью
- Добавьте метод для вывода информации о незавершенных курсах
- Реализуйте функцию, которая формирует список отличников
При выполнении этих заданий фокусируйтесь не только на технической реализации, но и на логической структуре классов. Хорошо спроектированный класс должен быть интуитивно понятным, с четко определенной ответственностью и минимальными зависимостями. 📊
Практические задания по ООП на Python на этом уровне закладывают критически важный фундамент. Без твердого понимания базовых принципов работы с классами и объектами невозможно двигаться дальше к более сложным концепциям вроде наследования и полиморфизма.
Наследование и полиморфизм: задания среднего уровня
Наследование и полиморфизм — ключевые механизмы ООП, позволяющие создавать гибкие и расширяемые программные системы. Практические задания по ООП на Python на этом уровне требуют уже более глубокого понимания связей между классами.
Практическое задание: Система учёта транспортных средств
Создайте базовый класс Vehicle и несколько дочерних классов, демонстрирующих наследование и полиморфизм.
class Vehicle:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
self.fuel = 0
self.mileage = 0
def refuel(self, amount):
self.fuel += amount
def drive(self, distance):
pass # Будет реализовано в дочерних классах
def get_info(self):
return f"{self.year} {self.make} {self.model}, Пробег: {self.mileage} км"
class Car(Vehicle):
def __init__(self, make, model, year, fuel_efficiency):
super().__init__(make, model, year)
self.fuel_efficiency = fuel_efficiency # км/л
def drive(self, distance):
required_fuel = distance / self.fuel_efficiency
if self.fuel >= required_fuel:
self.fuel -= required_fuel
self.mileage += distance
return f"Проехали {distance} км"
else:
return "Недостаточно топлива"
class ElectricCar(Vehicle):
def __init__(self, make, model, year, battery_capacity):
super().__init__(make, model, year)
self.battery_capacity = battery_capacity # кВт·ч
self.charge = 0
def refuel(self, amount): # Переопределение метода
self.charge = min(100, self.charge + amount)
return f"Заряд батареи: {self.charge}%"
def drive(self, distance):
consumption = distance / (self.battery_capacity * 5) # Примерный расчет
if consumption <= self.charge:
self.charge -= consumption
self.mileage += distance
return f"Проехали {distance} км, осталось заряда: {self.charge:.1f}%"
else:
return "Недостаточно заряда"
Практические задания с этими классами:
- Создайте класс
Motorcycle, наследующий отVehicle - Реализуйте класс
HybridCar, сочетающий свойстваCarиElectricCar - Создайте класс
Fleet, управляющий коллекцией транспортных средств - Добавьте метод для расчета общих затрат на топливо для всех автомобилей в парке
Задание: Банковская система с разными типами счетов
| Тип счета | Особенности | Примеры реализации |
|---|---|---|
| Базовый счет | Простое хранение и снятие средств | Класс с методами deposit() и withdraw() |
| Сберегательный счет | Ежемесячное начисление процентов | Наследование + метод add_interest() |
| Кредитный счет | Возможность уходить в минус, начисление процентов на задолженность | Переопределение метода withdraw() с новой логикой |
| Инвестиционный счет | Различные инструменты инвестирования с разными рисками | Композиция с классами различных инвестиционных инструментов |
class Account:
def __init__(self, owner, balance=0):
self.owner = owner
self.balance = balance
self.transactions = []
def deposit(self, amount):
self.balance += amount
self.transactions.append(("deposit", amount))
return self.balance
def withdraw(self, amount):
if amount > self.balance:
return False
self.balance -= amount
self.transactions.append(("withdraw", amount))
return True
def get_balance(self):
return self.balance
class SavingsAccount(Account):
def __init__(self, owner, balance=0, interest_rate=0.01):
super().__init__(owner, balance)
self.interest_rate = interest_rate
def add_interest(self):
interest = self.balance * self.interest_rate
self.deposit(interest)
self.transactions.append(("interest", interest))
return interest
class CheckingAccount(Account):
def __init__(self, owner, balance=0, transaction_limit=1000):
super().__init__(owner, balance)
self.transaction_limit = transaction_limit
def withdraw(self, amount):
if amount > self.transaction_limit:
return False
return super().withdraw(amount)
Задания для практики:
- Создайте класс
CreditAccountс лимитом кредита и процентной ставкой по задолженности - Реализуйте класс
Bank, который управляет всеми счетами клиента - Добавьте функционал для перевода средств между разными типами счетов
- Реализуйте систему учета комиссий за определенные операции
Наследование позволяет выстраивать иерархии классов, а полиморфизм обеспечивает единообразный интерфейс для разных типов объектов. Эти концепции критически важны для создания гибких систем, которые можно легко масштабировать и модифицировать. 🔄
При выполнении этих заданий обратите внимание на правильное использование метода super() для вызова методов родительского класса и на продуманное переопределение методов в дочерних классах. Полиморфизм проявляется, когда вы можете работать с объектами разных классов через общий интерфейс базового класса.
Анна Дмитриева, руководитель отдела разработки:
В нашей команде был случай, когда джуниор-разработчик пытался создать управление разными типами платежей в финтех-приложении без использования наследования. Он реализовал десятки условных операторов в одной функции, проверяющих тип платежа. Когда добавили новый тип платежа, всё развалилось. Мы провели рефакторинг, создав базовый класс Payment с методом process(), который каждый дочерний класс (CreditCardPayment, BankTransfer и т.д.) реализовывал по-своему. Код сократился на 60%, а добавление нового типа платежа теперь занимает 15 минут вместо дня отладки. Этот кейс я использую как наглядную демонстрацию силы полиморфизма.
Инкапсуляция и атрибуты: интенсивные практикумы
Инкапсуляция — краеугольный камень объектно-ориентированного программирования, позволяющий скрывать внутреннюю реализацию класса и предоставлять контролируемый доступ к его состоянию. В Python инкапсуляция реализуется с помощью соглашений об именовании и свойств (properties). Практические задания по ООП на Python должны уделять особое внимание этому аспекту.
Задание: Создание защищённой системы учёта данных
Разработайте класс User с защищёнными атрибутами и контролируемым доступом через свойства.
class User:
def __init__(self, username, email, password):
self._username = username # защищённый атрибут
self._email = email # защищённый атрибут
self.__password = password # приватный атрибут
self._login_attempts = 0
@property
def username(self):
return self._username
@username.setter
def username(self, value):
if len(value) < 3:
raise ValueError("Имя пользователя должно содержать минимум 3 символа")
self._username = value
@property
def email(self):
return self._email
@email.setter
def email(self, value):
if '@' not in value:
raise ValueError("Некорректный адрес электронной почты")
self._email = value
def verify_password(self, password_attempt):
if password_attempt == self.__password:
self._login_attempts = 0
return True
else:
self._login_attempts += 1
return False
def reset_password(self, old_password, new_password):
if self.verify_password(old_password):
self.__password = new_password
return True
return False
@property
def is_locked(self):
return self._login_attempts >= 3
def unlock(self, admin_code):
if admin_code == "admin123": # Упрощенно для примера
self._login_attempts = 0
return True
return False
Практические задания с этим классом:
- Реализуйте класс
AdminUser, наследующийся отUser, с дополнительными привилегиями - Создайте систему для отслеживания попыток взлома аккаунта
- Добавьте механизм временной блокировки аккаунта после нескольких неудачных попыток входа
- Разработайте класс
UserDatabaseдля управления коллекцией пользователей с безопасным хранением данных
Задание: Симуляция банкомата с защитой от несанкционированного доступа
class ATM:
def __init__(self, bank_name, location):
self._bank_name = bank_name
self._location = location
self.__available_cash = 100000 # Приватный атрибут
self.__daily_withdrawal_limit = 2000
self.__transactions = []
@property
def bank_info(self):
return f"{self._bank_name} ATM at {self._location}"
def check_balance(self, card, pin):
if self.__authenticate(card, pin):
return card.get_balance()
return "Ошибка аутентификации"
def withdraw(self, card, pin, amount):
if not self.__authenticate(card, pin):
return "Ошибка аутентификации"
if amount > self.__daily_withdrawal_limit:
return f"Превышен дневной лимит снятия ({self.__daily_withdrawal_limit})"
if amount > self.__available_cash:
return "В банкомате недостаточно наличных"
if card.withdraw(amount):
self.__available_cash -= amount
self.__log_transaction(card.number, "withdraw", amount)
return f"Выдано: {amount}"
else:
return "Недостаточно средств на счете"
def deposit(self, card, pin, amount):
if not self.__authenticate(card, pin):
return "Ошибка аутентификации"
card.deposit(amount)
self.__available_cash += amount
self.__log_transaction(card.number, "deposit", amount)
return f"Внесено на счет: {amount}"
def __authenticate(self, card, pin):
# Приватный метод для проверки подлинности
return card.verify_pin(pin)
def __log_transaction(self, card_number, transaction_type, amount):
# Приватный метод для логирования транзакций
import datetime
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
transaction = {
"timestamp": timestamp,
"card": card_number[-4:], # Только последние 4 цифры для безопасности
"type": transaction_type,
"amount": amount
}
self.__transactions.append(transaction)
def get_transaction_history(self, admin_key):
# Только для обслуживающего персонала
if admin_key != "secret_admin_key":
return "Доступ запрещен"
return self.__transactions
def refill(self, admin_key, amount):
if admin_key != "secret_admin_key":
return "Доступ запрещен"
self.__available_cash += amount
return f"Банкомат пополнен на {amount}"
Задачи для практики:
- Создайте класс
BankCardс защищёнными данными и методом проверки PIN-кода - Реализуйте механизм блокировки карты после трёх неудачных попыток ввода PIN
- Добавьте систему мониторинга подозрительных транзакций
- Разработайте класс
ATMNetworkдля управления сетью банкоматов
Дополнительные практические задания по инкапсуляции:
- Создайте класс для управления паролями, который хранит их в зашифрованном виде
- Разработайте систему для работы с конфиденциальными медицинскими данными
- Реализуйте класс для безопасного хранения и передачи платежной информации
- Создайте класс-обертку для работы с API, который скрывает ключи доступа
Инкапсуляция — это не только технический механизм, но и принцип проектирования, который делает код более надежным и предсказуемым. Правильное использование инкапсуляции значительно снижает вероятность ошибок и упрощает дальнейшую поддержку кода. 🔒
При работе с инкапсуляцией в Python важно помнить, что:
- Атрибуты с одним подчеркиванием (_attribute) считаются защищенными по соглашению
- Атрибуты с двумя подчеркиваниями (__attribute) подвергаются "искажению имени" (name mangling)
- Свойства (properties) предоставляют контролируемый доступ к атрибутам
- Декораторы @property, @attribute.setter и @attribute.deleter позволяют элегантно реализовать геттеры и сеттеры
Продвинутые практические задания по ООП на Python
Продвинутые практические задания по ООП на Python требуют комплексного применения всех принципов объектно-ориентированного программирования. Они моделируют реальные системы и подготавливают разработчика к решению сложных задач в промышленной разработке. 🚀
Задание: Реализация шаблонов проектирования
Шаблоны проектирования — это проверенные временем решения типичных проблем проектирования программного обеспечения. Практические задания в этой области помогают развить архитектурное мышление.
# Реализация шаблона Singleton
class DatabaseConnection:
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self, connection_string=None):
# Инициализация происходит только при первом создании
if not hasattr(self, 'initialized'):
self.connection_string = connection_string
self.connection_pool = []
self.initialized = True
def connect(self):
print(f"Connecting to database using {self.connection_string}")
# Реальная логика подключения
return True
def execute_query(self, query):
print(f"Executing query: {query}")
# Реальная логика выполнения запроса
return ["result1", "result2"]
# Реализация шаблона Factory
class LoggerFactory:
@staticmethod
def create_logger(logger_type):
if logger_type == "file":
return FileLogger()
elif logger_type == "database":
return DatabaseLogger()
elif logger_type == "console":
return ConsoleLogger()
else:
raise ValueError(f"Unknown logger type: {logger_type}")
class Logger:
def log(self, message):
raise NotImplementedError()
class FileLogger(Logger):
def __init__(self, filename="app.log"):
self.filename = filename
def log(self, message):
print(f"Writing to file {self.filename}: {message}")
class DatabaseLogger(Logger):
def __init__(self):
self.db = DatabaseConnection("log_db_connection")
def log(self, message):
self.db.execute_query(f"INSERT INTO logs VALUES ('{message}')")
class ConsoleLogger(Logger):
def log(self, message):
print(f"LOG: {message}")
Задания для практики:
- Реализуйте шаблон "Наблюдатель" (Observer) для системы уведомлений
- Создайте систему плагинов, используя шаблон "Стратегия"
- Разработайте кэширующий механизм с применением шаблона "Декоратор"
- Реализуйте шаблон "Команда" для системы управления историей операций
Задание: Разработка фреймворка для тестирования
Создайте простой фреймворк для юнит-тестирования, используя принципы ООП.
class TestCase:
def __init__(self, name):
self.name = name
self.setup_called = False
self.teardown_called = False
def setUp(self):
self.setup_called = True
def tearDown(self):
self.teardown_called = True
def run(self, result):
result.test_started(self)
self.setUp()
try:
method = getattr(self, self.name)
method()
except Exception as e:
result.test_failed(self, e)
else:
result.test_passed(self)
finally:
self.tearDown()
class TestResult:
def __init__(self):
self.runs = 0
self.failures = 0
self.errors = []
def test_started(self, test):
self.runs += 1
def test_failed(self, test, error):
self.failures += 1
self.errors.append((test, error))
def test_passed(self, test):
pass
def summary(self):
return f"Run: {self.runs}, Failed: {self.failures}"
class TestSuite:
def __init__(self):
self.tests = []
def add(self, test):
self.tests.append(test)
def run(self, result):
for test in self.tests:
test.run(result)
# Пример использования
class SampleTest(TestCase):
def test_addition(self):
self.assertEqual(1 + 1, 2)
def test_subtraction(self):
self.assertEqual(5 – 3, 2)
def assertEqual(self, a, b):
if a != b:
raise AssertionError(f"{a} != {b}")
Задания для практики:
- Добавьте поддержку различных типов утверждений (assertEqual, assertIn и т.д.)
- Реализуйте функционал пропуска тестов (skip) и условного выполнения
- Добавьте механизм для измерения времени выполнения тестов
- Реализуйте форматированный вывод результатов тестирования
Задание: Создание мини-фреймворка для веб-приложения
| Компонент | Ответственность | Ключевые концепции ООП |
|---|---|---|
| Router | Маршрутизация URL к обработчикам | Инкапсуляция, композиция |
| Request | Обработка входящего HTTP-запроса | Инкапсуляция, свойства |
| Response | Формирование HTTP-ответа | Инкапсуляция, полиморфизм |
| Middleware | Промежуточные обработчики запросов | Наследование, декораторы |
| View | Логика обработки запросов | Наследование, полиморфизм |
class Request:
def __init__(self, path, method="GET", headers=None, body=None):
self.path = path
self.method = method
self.headers = headers or {}
self.body = body
self._parsed_params = None
@property
def params(self):
if self._parsed_params is None:
# Парсинг параметров из пути или тела
if '?' in self.path:
query_string = self.path.split('?')[1]
params = {}
for param in query_string.split('&'):
key, value = param.split('=')
params[key] = value
self._parsed_params = params
else:
self._parsed_params = {}
return self._parsed_params
class Response:
def __init__(self, content="", status_code=200, headers=None):
self.content = content
self.status_code = status_code
self.headers = headers or {}
def set_content(self, content):
self.content = content
return self
def set_status(self, status_code):
self.status_code = status_code
return self
def set_header(self, key, value):
self.headers[key] = value
return self
def __str__(self):
headers_str = "\n".join(f"{k}: {v}" for k, v in self.headers.items())
return f"HTTP/1.1 {self.status_code}\n{headers_str}\n\n{self.content}"
class Router:
def __init__(self):
self.routes = {}
def add_route(self, path, handler, methods=None):
methods = methods or ["GET"]
for method in methods:
key = (method, path)
self.routes[key] = handler
def get_handler(self, request):
key = (request.method, request.path)
return self.routes.get(key)
class Application:
def __init__(self):
self.router = Router()
self.middlewares = []
def add_middleware(self, middleware):
self.middlewares.append(middleware)
def handle_request(self, request):
# Применение middlewares
for middleware in self.middlewares:
request = middleware(request)
handler = self.router.get_handler(request)
if handler:
return handler(request)
else:
return Response("Not Found", 404)
def route(self, path, methods=None):
def decorator(handler):
self.router.add_route(path, handler, methods)
return handler
return decorator
Задания для практики:
- Добавьте поддержку шаблонизатора для генерации HTML
- Реализуйте простую ORM для работы с базой данных
- Добавьте систему аутентификации и авторизации
- Реализуйте механизм для обработки статических файлов
Эти продвинутые практические задания по ООП на Python помогут вам не просто освоить синтаксические конструкции языка, но и научиться мыслить объектно-ориентированными абстракциями. Это ключевой навык для проектирования масштабируемых и поддерживаемых программных систем. 💻
Работа над такими заданиями требует не только хорошего понимания технических аспектов ООП, но и развития архитектурного мышления — умения видеть систему как совокупность взаимодействующих компонентов с четко определенными ответственностями.
Освоение ООП в Python через практические задания — это не просто изучение синтаксиса, а формирование нового образа мышления. Выполняя упражнения различной сложности, вы постепенно переходите от механического написания кода к осознанному проектированию систем. Вместо борьбы с сотнями строк запутанного процедурного кода вы научитесь создавать элегантные структуры классов, где каждый компонент выполняет чётко определённую функцию. Именно в этом и заключается сила объектно-ориентированного программирования — способность укротить сложность через абстракцию и инкапсуляцию.
Читайте также
- Чистый ООП: как писать код, который не превратится в кошмар
- Объектно-ориентированные языки программирования: принципы и выбор
- Программирование для начинающих: изучаем основы с нуля до практики
- Полное руководство по разработке ПО: от идеи до внедрения
- За рамками ООП: функциональное и процедурное программирование
- Объектно-ориентированное программирование: плюсы и минусы подхода
- ООП в C++: от теории к практике – задачи и решения для новичков
- ООП: четыре принципа разработки эффективного и чистого кода
- ООП в Java: как абстрактные концепции превращаются в прибыль
- Исходный код программы: как написать свою первую программу


