ООП Классы

Warning

Тема с классами обычно дается не сразу. Нормально, если сначала она кажется непривычной. Важно не только читать примеры, но и руками повторять код: создавать классы, объекты, менять атрибуты и запускать методы.

Tip

ИИ лучше использовать как помощника для объяснений и подсказок, а не как источник готовых решений. Если задача не получается, просите намек или разбор ошибки, но финальный код пишите самостоятельно.

Содержание

  1. Что такое класс и объект
  2. Как создать класс
  3. Атрибуты объекта
  4. Несколько объектов одного класса
  5. Конструктор __init__
  6. Методы и self
  7. Атрибуты класса и атрибуты объекта
  8. Практика

Что такое класс и объект

Класс - это шаблон, по которому создаются объекты. В классе описывают, какие данные будут храниться у объекта и какие действия он сможет выполнять.

Объект - это конкретный экземпляр класса. У каждого объекта могут быть собственные значения атрибутов, хотя структура у них будет общей.

Пример из жизни: User - это общий шаблон пользователя, а user1 и user2 - конкретные пользователи с разными именами, возрастом и статусом.

class User:
    pass
 
user1 = User()
user2 = User()

User - класс. user1 и user2 - объекты, созданные на основе этого класса.


Как создать класс

Для создания класса используется ключевое слово class.

class ClassName:
    pass

pass нужен, когда тело класса пока пустое. Python требует, чтобы внутри класса был хотя бы один оператор.

По стилю PEP 8 имена классов пишут в CamelCase: UserProfile, BankAccount, ApiClient. Имена функций и переменных обычно пишут в snake_case.

class Human:
    pass
 
human1 = Human()
human2 = Human()
 
print(type(human1))
print(human1 is human2)  # False

Каждый вызов Human() создает новый независимый объект.


Атрибуты объекта

Атрибут - это переменная, которая принадлежит конкретному объекту. К атрибутам обращаются через точку.

class Student:
    pass
 
student = Student()
student.name = "Алина"
student.grade = 10
student.is_present = True
 
print(student.name)
print(student.grade)
print(student.is_present)

Запись student.name означает: взять атрибут name у объекта student.

Атрибуты можно менять:

student.grade = 11
print(student.grade)

Но если атрибут не был создан, попытка обратиться к нему вызовет AttributeError.


Несколько объектов одного класса

Объекты одного класса создаются по одному шаблону, но их данные не обязаны совпадать.

class Product:
    pass
 
product1 = Product()
product1.name = "Клавиатура"
product1.price = 3500
product1.in_stock = True
 
product2 = Product()
product2.name = "Монитор"
product2.price = 18000
product2.in_stock = False
 
print(product1.name, product1.price)
print(product2.name, product2.price)

Изменение атрибута у одного объекта не меняет второй объект.

product1.price = 3200
print(product1.price)  # 3200
print(product2.price)  # 18000

Конструктор __init__

Обычно атрибуты задают сразу при создании объекта. Для этого используют специальный метод __init__.

class Student:
    def __init__(self, name, grade):
        self.name = name
        self.grade = grade
 
student1 = Student("Ирина", 9)
student2 = Student("Максим", 11)
 
print(student1.name, student1.grade)
print(student2.name, student2.grade)

__init__ вызывается автоматически, когда создается объект. Параметр self указывает на конкретный объект, который сейчас создается.

Что происходит в строке Student("Ирина", 9):

  1. Python создает новый объект класса Student.
  2. Вызывает __init__.
  3. Передает новый объект в self.
  4. Записывает значения в self.name и self.grade.

Методы и self

Метод - это функция, которая находится внутри класса и работает с объектом. Как устроены функции сами по себе, мы разбирали в 03.01 - Функции.

class BankAccount:
    def __init__(self, owner, balance=0):
        self.owner = owner
        self.balance = balance
 
    def deposit(self, amount):
        self.balance += amount
        print(f"Баланс пополнен на {amount}")
 
    def get_info(self):
        return f"Счет {self.owner}: {self.balance} руб."
 
account = BankAccount("Олег", 1000)
account.deposit(500)
print(account.get_info())

self нужен, чтобы метод понимал, с каким именно объектом он работает. Если есть два счета, каждый метод будет менять данные только своего объекта.

account1 = BankAccount("Олег", 1000)
account2 = BankAccount("Нина", 2000)
 
account1.deposit(300)
 
print(account1.get_info())
print(account2.get_info())

Типичная ошибка новичков - забыть self в объявлении метода.

class WrongExample:
    def show_name():
        print(self.name)  # ошибка

Правильно:

class CorrectExample:
    def __init__(self, name):
        self.name = name
 
    def show_name(self):
        print(self.name)

Атрибуты класса и атрибуты объекта

Атрибут объекта принадлежит конкретному экземпляру. Атрибут класса общий для класса и может использоваться всеми объектами.

class Counter:
    total_created = 0  # атрибут класса
 
    def __init__(self, name):
        self.name = name      # атрибут объекта
        self.value = 0        # атрибут объекта
        Counter.total_created += 1
 
counter1 = Counter("Первый")
counter2 = Counter("Второй")
 
print(counter1.name)
print(counter2.name)
print(Counter.total_created)

name и value у каждого объекта свои. total_created хранится на уровне класса и считает, сколько объектов создано.


Практика

  • Задание 1: первые классы

    Создать класс Notebook. У объекта должны быть атрибуты title, pages, is_finished. Создайте два объекта и выведите информацию о каждом.

    class Notebook:
        pass
     
    notebook1 = Notebook()
    notebook1.title = "Python notes"
    notebook1.pages = 64
    notebook1.is_finished = False
     
    notebook2 = Notebook()
    notebook2.title = "QA checklist"
    notebook2.pages = 32
    notebook2.is_finished = True
  • Задание 2: конструктор

    Создать класс CourseStudent с конструктором __init__(self, name, score). Добавить метод get_status(), который возвращает Сдал, если score >= 70, иначе Нужно повторить.

    class CourseStudent:
        def __init__(self, name, score):
            self.name = name
            self.score = score
     
        def get_status(self):
            if self.score >= 70:
                return "Сдал"
            return "Нужно повторить"
     
    student = CourseStudent("Марина", 82)
    print(student.get_status())
  • Задание 3: методы калькулятора

    Создать класс Calculator с методами add, subtract, multiply, divide. В divide добавить проверку деления на ноль.

    class Calculator:
        def add(self, a, b):
            return a + b
     
        def subtract(self, a, b):
            return a - b
     
        def multiply(self, a, b):
            return a * b
     
        def divide(self, a, b):
            if b == 0:
                return "Ошибка: деление на ноль"
            return a / b
     
    calc = Calculator()
    print(calc.add(12, 8))
    print(calc.divide(15, 0))
  • Задание 4: счет с изменением состояния

    Создать класс BankAccount с атрибутами owner_name, balance, transaction_count и методами deposit, withdraw, get_balance, get_info.

    Требования:

    • пополнение возможно только на положительную сумму;
    • снятие возможно только если денег достаточно;
    • каждая успешная операция увеличивает transaction_count;
    • get_info() возвращает строку с владельцем, балансом и количеством операций.
  • Задание 5: работа с self

    Создать класс Person с атрибутами name и age. Добавить методы introduce() и have_birthday(). Создать три объекта и проверить, что изменение возраста одного объекта не влияет на остальные.

    class Person:
        def __init__(self, name, age):
            self.name = name
            self.age = age
     
        def introduce(self):
            print(f"Меня зовут {self.name}, мне {self.age} лет")
     
        def have_birthday(self):
            self.age += 1
            print(f"Теперь {self.name}: {self.age}")
  • Задание 6: прямоугольники

    Создать класс Rectangle с атрибутами width и height.

    Методы:

    • area() - возвращает площадь;
    • perimeter() - возвращает периметр;
    • is_square() - возвращает True, если это квадрат;
    • scale(factor) - увеличивает размеры в factor раз;
    • compare_area(other_rectangle) - сравнивает площади двух прямоугольников.

    Измените размеры и значения относительно примеров из теории, чтобы проверить, что логика работает на разных данных.

  • Задание 7: взаимодействие объектов

    Создать класс Player с атрибутами name, health, max_health, attack_power, is_alive.

    Методы:

    • attack(target) - атакует другой объект;
    • take_damage(damage) - уменьшает здоровье;
    • heal(amount) - восстанавливает здоровье, но не выше max_health;
    • get_status() - возвращает текущий статус игрока.

    Создайте двух игроков с другими именами и значениями здоровья, чем в примерах, и проведите несколько раундов.

  • Задание 8: мини-проект

    Спроектировать простую систему магазина с классами Product и ShoppingCart.

    Product должен хранить name, price, category, stock и иметь методы get_info(), is_available(), reduce_stock(amount), add_stock(amount).

    ShoppingCart должен хранить имя покупателя и товары в корзине. Добавьте методы add_item, remove_item, calculate_total, get_cart_info, checkout.


Короткий итог

Класс описывает структуру будущих объектов. Объект хранит конкретные данные. Атрибуты описывают состояние, методы - поведение, __init__ подготавливает объект при создании, а self связывает метод с конкретным экземпляром. Если эти идеи стали понятны, дальше ООП воспринимается намного спокойнее.


⬅️ Назад: 03.03 - ООП Общая теория | Далее: 03.05 - Наследование ➡️ Модуль: 03 - MOC