Объектно-ориентированное программирование (ООП) - это парадигма программирования, основанная на использовании объектов и классов. Python полностью поддерживает ООП, что делает его мощным инструментом для создания сложных приложений.
Класс в Python создается с помощью ключевого слова class:
# Простой класс
class Человек:
pass # Пустой класс
# Создание объекта (экземпляра класса)
человек1 = Человек()
print(type(человек1)) # <class '__main__.Человек'>
# Класс с атрибутами
class Автомобиль:
# Атрибуты класса
количество_колес = 4
тип_двигателя = "бензиновый"
# Создание объектов
машина1 = Автомобиль()
машина2 = Автомобиль()
# Доступ к атрибутам класса
print(f"Количество колес: {машина1.количество_колес}")
print(f"Тип двигателя: {машина2.тип_двигателя}")
# Изменение атрибута класса
Автомобиль.количество_колес = 6
print(f"Новое количество колес: {машина1.количество_колес}")
Метод __init__ - это специальный метод, который автоматически вызывается при создании объекта:
class Студент:
def __init__(self, имя, возраст, курс):
# Атрибуты экземпляра
self.имя = имя
self.возраст = возраст
self.курс = курс
self.оценки = []
def представиться(self):
return f"Меня зовут {self.имя}, мне {self.возраст} лет, я учусь на {self.курс} курсе"
def добавить_оценку(self, оценка):
self.оценки.append(оценка)
def средний_балл(self):
if not self.оценки:
return 0
return sum(self.оценки) / len(self.оценки)
# Создание объектов с параметрами
студент1 = Студент("Анна", 20, 2)
студент2 = Студент("Борис", 22, 4)
# Использование методов
print(студент1.представиться())
print(студент2.представиться())
# Работа с оценками
студент1.добавить_оценку(5)
студент1.добавить_оценку(4)
студент1.добавить_оценку(5)
print(f"Средний балл {студент1.имя}: {студент1.средний_балл()}")
В Python есть три типа методов: методы экземпляра, методы класса и статические методы:
class Математика:
число_pi = 3.14159
# Метод экземпляра (первый параметр - self)
def умножить_на_пи(self, число):
return число * self.число_pi
# Метод класса (первый параметр - cls)
@classmethod
def установить_пи(cls, новое_значение):
cls.число_pi = новое_значение
# Статический метод (не принимает self или cls)
@staticmethod
def сложить(a, b):
return a + b
# Использование методов
математика = Математика()
# Метод экземпляра
print(f"5 * π = {математика.умножить_на_пи(5)}")
# Метод класса
Математика.установить_пи(3.14)
print(f"Новое значение π: {Математика.число_pi}")
# Статический метод
print(f"Сумма 3 + 7 = {Математика.сложить(3, 7)}")
Python позволяет контролировать доступ к атрибутам с помощью свойств и соглашений об именовании:
class БанковскийСчет:
def __init__(self, владелец, баланс=0):
self.владелец = владелец
self.__баланс = баланс # Приватный атрибут (два подчеркивания)
self._история = [] # Защищенный атрибут (одно подчеркивание)
# Свойство для доступа к балансу
@property
def баланс(self):
return self.__баланс
# Свойство для установки баланса с проверкой
@баланс.setter
def баланс(self, значение):
if значение < 0:
raise ValueError("Баланс не может быть отрицательным")
self.__баланс = значение
def пополнить(self, сумма):
if сумма <= 0:
raise ValueError("Сумма должна быть положительной")
self.__баланс += сумма
self._история.append(f"Пополнение на {сумма}")
return self.__баланс
def снять(self, сумма):
if сумма <= 0:
raise ValueError("Сумма должна быть положительной")
if сумма > self.__баланс:
raise ValueError("Недостаточно средств")
self.__баланс -= сумма
self._история.append(f"Снятие {сумма}")
return self.__баланс
def показать_историю(self):
return self._история
# Использование класса
счет = БанковскийСчет("Иван Иванов", 1000)
# Доступ к публичному атрибуту
print(f"Владелец: {счет.владелец}")
# Доступ к приватному атрибуту через свойство
print(f"Баланс: {счет.баланс}")
# Изменение баланса через свойство
try:
счет.баланс = 2000
print(f"Новый баланс: {счет.баланс}")
except ValueError as e:
print(f"Ошибка: {e}")
# Операции со счетом
try:
счет.пополнить(500)
print(f"Баланс после пополнения: {счет.баланс}")
счет.снять(300)
print(f"Баланс после снятия: {счет.баланс}")
except ValueError as e:
print(f"Ошибка: {e}")
# Просмотр истории
print("История операций:")
for операция in счет.показать_историю():
print(f"- {операция}")
Python предоставляет множество специальных методов, которые позволяют определять поведение объектов:
class КомплексноеЧисло:
def __init__(self, действительная, мнимая):
self.действительная = действительная
self.мнимая = мнимая
# Метод для строкового представления объекта
def __str__(self):
if self.мнимая >= 0:
return f"{self.действительная} + {self.мнимая}i"
else:
return f"{self.действительная} - {abs(self.мнимая)}i"
# Метод для "официального" строкового представления
def __repr__(self):
return f"КомплексноеЧисло({self.действительная}, {self.мнимая})"
# Метод для сложения двух комплексных чисел
def __add__(self, другое):
if isinstance(другое, КомплексноеЧисло):
return КомплексноеЧисло(
self.действительная + другое.действительная,
self.мнимая + другое.мнимая
)
return NotImplemented
# Метод для проверки равенства
def __eq__(self, другое):
if isinstance(другое, КомплексноеЧисло):
return (self.действительная == другое.действительная and
self.мнимая == другое.мнимая)
return False
# Использование специальных методов
число1 = КомплексноеЧисло(3, 4)
число2 = КомплексноеЧисло(1, -2)
# Использование __str__
print(f"Число 1: {число1}")
print(f"Число 2: {число2}")
# Использование __repr__
print(f"repr: {repr(число1)}")
# Использование __add__
сумма = число1 + число2
print(f"Сумма: {сумма}")
# Использование __eq__
число3 = КомплексноеЧисло(3, 4)
print(f"число1 == число3: {число1 == число3}")
print(f"число1 == число2: {число1 == число2}")
Рассмотрим несколько практических примеров использования классов:
class Книга:
def __init__(self, название, автор, год_издания, isbn):
self.название = название
self.автор = автор
self.год_издания = год_издания
self.isbn = isbn
self.доступна = True
def __str__(self):
статус = "доступна" if self.доступна else "выдана"
return f"'{self.название}' by {self.автор} ({self.год_издания}) - {статус}"
class Библиотека:
def __init__(self, название):
self.название = название
self.книги = []
def добавить_книгу(self, книга):
self.книги.append(книга)
print(f"Книга '{книга.название}' добавлена в библиотеку")
def найти_книгу(self, название):
for книга in self.книги:
if название.lower() in книга.название.lower():
return книга
return None
def выдать_книгу(self, название):
книга = self.найти_книгу(название)
if книга and книга.доступна:
книга.доступна = False
print(f"Книга '{книга.название}' выдана")
elif книга:
print(f"Книга '{книга.название}' уже выдана")
else:
print(f"Книга '{название}' не найдена")
def вернуть_книгу(self, название):
книга = self.найти_книгу(название)
if книга and not книга.доступна:
книга.доступна = True
print(f"Книга '{книга.название}' возвращена")
elif книга:
print(f"Книга '{книга.название}' уже в библиотеке")
else:
print(f"Книга '{название}' не найдена в библиотеке")
def показать_все_книги(self):
if not self.книги:
print("Библиотека пуста")
return
print(f"\nКниги в библиотеке '{self.название}':")
for i, книга in enumerate(self.книги, 1):
print(f"{i}. {книга}")
# Использование системы библиотеки
библиотека = Библиотека("Городская библиотека")
# Добавление книг
библиотека.добавить_книгу(Книга("Война и мир", "Л.Н. Толстой", 1869, "978-5-17-006400-7"))
библиотека.добавить_книгу(Книга("Преступление и наказание", "Ф.М. Достоевский", 1866, "978-5-17-006500-4"))
библиотека.добавить_книгу(Книга("Мастер и Маргарита", "М.А. Булгаков", 1967, "978-5-17-082100-5"))
# Просмотр всех книг
библиотека.показать_все_книги()
# Работа с книгами
библиотека.выдать_книгу("Война и мир")
библиотека.выдать_книгу("Война и мир") # Попытка повторной выдачи
библиотека.вернуть_книгу("Война и мир")
библиотека.вернуть_книгу("Неизвестная книга") # Попытка вернуть несуществующую книгу
Задание 1:
class Автомобиль:
def __init__(self, марка, модель, год_выпуска, пробег=0):
self.марка = марка
self.модель = модель
self.год_выпуска = год_выпуска
self.пробег = пробег
def увеличить_пробег(self, расстояние):
if расстояние < 0:
raise ValueError("Расстояние не может быть отрицательным")
self.пробег += расстояние
print(f"Пробег увеличен на {расстояние} км. Общий пробег: {self.пробег} км")
def получить_информацию(self):
return (f"{self.марка} {self.модель} ({self.год_выпуска})\n"
f"Пробег: {self.пробег} км")
def __str__(self):
return self.получить_информацию()
# Пример использования
авто = Автомобиль("Toyota", "Camry", 2020, 15000)
print(авто)
авто.увеличить_пробег(500)
print(авто)
Задание 2:
import math
class Треугольник:
def __init__(self, сторона_a, сторона_b, сторона_c):
self.сторона_a = сторона_a
self.сторона_b = сторона_b
self.сторона_c = сторона_c
if not self.существует():
raise ValueError("Треугольник с такими сторонами не существует")
def существует(self):
# Проверка неравенства треугольника
return (self.сторона_a + self.сторона_b > self.сторона_c and
self.сторона_a + self.сторона_c > self.сторона_b and
self.сторона_b + self.сторона_c > self.сторона_a)
def периметр(self):
return self.сторона_a + self.сторона_b + self.сторона_c
def площадь(self):
# Формула Герона
p = self.периметр() / 2
return math.sqrt(p * (p - self.сторона_a) * (p - self.сторона_b) * (p - self.сторона_c))
def __str__(self):
return (f"Треугольник со сторонами: {self.сторона_a}, {self.сторона_b}, {self.сторона_c}\n"
f"Периметр: {self.периметр()}\n"
f"Площадь: {self.площадь():.2f}")
# Пример использования
try:
треугольник = Треугольник(3, 4, 5)
print(треугольник)
except ValueError as e:
print(f"Ошибка: {e}")
Задание 3:
class Счет:
def __init__(self, номер, баланс=0):
self.номер = номер
self.баланс = баланс
class Банк:
def __init__(self, название):
self.название = название
self.счета = []
def создать_счет(self, номер, начальный_баланс=0):
счет = Счет(номер, начальный_баланс)
self.счета.append(счет)
print(f"Счет {номер} создан с балансом {начальный_баланс}")
return счет
def перевести_деньги(self, номер_отправителя, номер_получателя, сумма):
отправитель = next((счет for счет in self.счета if счет.номер == номер_отправителя), None)
получатель = next((счет for счет in self.счета if счет.номер == номер_получателя), None)
if not отправитель:
print(f"Счет отправителя {номер_отправителя} не найден")
return False
if not получатель:
print(f"Счет получателя {номер_получателя} не найден")
return False
if отправитель.баланс < сумма:
print(f"Недостаточно средств на счете {номер_отправителя}")
return False
отправитель.баланс -= сумма
получатель.баланс += сумма
print(f"Переведено {сумма} со счета {номер_отправителя} на счет {номер_получателя}")
return True
def общая_сумма(self):
return sum(счет.баланс for счет in self.счета)
def показать_счета(self):
print(f"\nСчета в банке '{self.название}':")
for счет in self.счета:
print(f"Счет {счет.номер}: {счет.баланс}")
# Пример использования
банк = Банк("Мой Банк")
счет1 = банк.создать_счет("ACC001", 1000)
счет2 = банк.создать_счет("ACC002", 500)
банк.показать_счета()
print(f"Общая сумма: {банк.общая_сумма()}")
банк.перевести_деньги("ACC001", "ACC002", 300)
банк.показать_счета()
print(f"Общая сумма: {банк.общая_сумма()}")
Задание 4:
class Калькулятор:
def __init__(self):
self.история = []
def сложить(self, a, b):
результат = a + b
операция = f"{a} + {b} = {результат}"
self.история.append(операция)
return результат
def вычесть(self, a, b):
результат = a - b
операция = f"{a} - {b} = {результат}"
self.история.append(операция)
return результат
def умножить(self, a, b):
результат = a * b
операция = f"{a} * {b} = {результат}"
self.история.append(операция)
return результат
def разделить(self, a, b):
if b == 0:
raise ZeroDivisionError("Деление на ноль невозможно")
результат = a / b
операция = f"{a} / {b} = {результат}"
self.история.append(операция)
return результат
def показать_историю(self):
if not self.история:
print("История пуста")
return
print("История вычислений:")
for операция in self.история:
print(f"- {операция}")
def очистить_историю(self):
self.история.clear()
print("История очищена")
# Пример использования
калькулятор = Калькулятор()
print(f"Сложение: {калькулятор.сложить(5, 3)}")
print(f"Вычитание: {калькулятор.вычесть(10, 4)}")
print(f"Умножение: {калькулятор.умножить(7, 2)}")
try:
print(f"Деление: {калькулятор.разделить(15, 3)}")
print(f"Деление на ноль: {калькулятор.разделить(10, 0)}")
except ZeroDivisionError as e:
print(f"Ошибка: {e}")
калькулятор.показать_историю()