Классы и объекты Python: учебник ООП с реальными примерами

  1. Главная
  2. Блог
  3. Разработка программного обеспечения

Разработка программного обеспечения

Классы и объекты Python: Урок ООП с реальными примерами

Изучите объектно-ориентированный Python, создавая что-то реальное. Создавайте классы, разбирайтесь в self и __init__, делитесь поведением с помощью наследования, защищайте данные с помощью свойств и знайте, когда класс является неподходящим инструментом.

10 мин чтения
Классы и объекты Python: учебник ООП с реальными примерами

Главное

  • класс — это проект, а объект — это что-то, построенное на его основе.
  • __init__ устанавливает каждый новый объект, а self ссылается на этот объект.
  • Атрибуты, установленные в классе, являются общими. Атрибуты, установленные в self, принадлежат одному объекту.
  • Используйте @dataclass для классов, содержащих данные, и отдавайте предпочтение простым функциям, когда нет состояния, которое нужно сохранять.

По мере роста сценария вы в конечном итоге передаете одну и ту же группу переменных между функциями, и становится трудно определить, какие данные и какой логике принадлежат. Классы и объекты Python решают эту проблему, объединяя данные и поведение в один блок.

В этом уроке мы шаг за шагом создаем небольшой банковский счет и добавляем каждую идею ООП только тогда, когда она решает проблему. Мы запускали каждый пример на Python 3.13, и показанный результат получен в результате этого запуска. Если вы новичок в этом языке, сначала прочитайте наше Урок по Python для начинающих.

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

Класс описывает, что представляет собой объект и что он может делать. объект, также называемый экземпляром, — это особый объект, созданный на основе этого описания. «Учетная запись» — это класс, а учетная запись Аши и учетная запись Бена — два объекта.

Срок Значение Пример
Класс План Аккаунт
Объект или экземпляр Из него сделана одна вещь a = Аккаунт("Аша")
Атрибут Данные об объекте a.balance
Метод Функция в классе a.deposit(50)

Вы все время использовали объекты. В Python строки, списки и даже функции являются объектами, поэтому вы можете написать "hello".upper().

Ваш первый урок

class Account:
    def __init__(self, owner, balance=0):
        self.owner = owner
        self.balance = balance

    def deposit(self, amount):
        if amount <= 0:
            raise ValueError("amount must be positive")
        self.balance += amount
        return self.balance

a = Account("Asha", 100)
b = Account("Ben")

a.deposit(50)
print(a.balance, b.balance)

# 150 0

__init__ запускается автоматически всякий раз, когда вы создаете объект, и устанавливает начальное состояние. Внесение в a не коснулось b, потому что у каждого объекта свои данные. Обратите внимание, что этот метод также защищает баланс от неправильного значения. Наше руководство по Обработке исключений Python объясняет raise более подробно.

Что такое сам?

self — это просто объект, над которым работает метод. Когда вы пишете a.deposit(50), Python фактически вызывает Account.deposit(a, 50), передавая объект в качестве первого аргумента. Вот как одно определение метода может обслуживать каждый объект.

Имя self является строгим соглашением, а не ключевым словом, но всегда используйте его. Забыть его в определении метода — самая распространенная ошибка новичков, которая приводит к сбивчивому сообщению о количестве аргументов.

Атрибуты класса и атрибуты экземпляра

Атрибут, установленный непосредственно в теле класса, является общим для всех объектов. Один набор в self принадлежит только этому объекту. В этом примере показано, как ведут себя поисковые запросы:

class Account:
    interest_rate = 0.04    # class attribute

    def __init__(self, owner, balance=0):
        self.owner = owner  # instance attribute
        self.balance = balance

a = Account("Asha", 100)
b = Account("Ben")
print(a.interest_rate, b.interest_rate)   # 0.04 0.04

Account.interest_rate = 0.05
print(a.interest_rate, b.interest_rate)   # 0.05 0.05

a.interest_rate = 0.09
print(a.interest_rate, b.interest_rate, Account.interest_rate)
# 0.09 0.05 0.05

Последняя строка удивляет людей. Назначение через a не изменило общее значение. Он создал новый атрибут экземпляра в a, который скрывает атрибут класса. Python сначала просматривает объект, затем класс.

Специальные (дандер) методы

Методы с двойным подчеркиванием позволяют вашим объектам работать со встроенными функциями Python. Без них печать аккаунта показывает бесполезный адрес памяти. Добавление двух придает ему читаемую форму:

    def __str__(self):
        return f"{self.owner}: {self.balance}"

    def __repr__(self):
        return f"Account({self.owner!r}, {self.balance})"

print(a)        # Asha: 150
print([a, b])   # [Account('Asha', 150), Account('Ben', 0)]
Метод По инициативе
__init__ Создание объекта
__str__ print(obj), str(obj)
__repr__ Отладка или отображение в списке
__eq__ а == б
__len__ len(obj)
__add__ а + б

Наследование

Наследование позволяет новому классу повторно использовать существующий и изменять только то, что отличается. Здесь Savings — это Account с дополнительной настройкой:

class Savings(Account):
    def __init__(self, owner, balance=0, limit=3):
        super().__init__(owner, balance)
        self.limit = limit

    def __str__(self):
        return f"{super().__str__()} (savings)"

s = Savings("Chitra", 500)
s.deposit(100)
print(s, isinstance(s, Account), s.limit)

# Chitra: 600 (savings) True 3

super() вызывает родительскую версию, поэтому логика установки не повторяется. deposit было унаследовано как есть, а __str__ было переопределено для добавления метки. Используйте наследование только для реальных отношений «есть». Если классу просто что-то нужно, например, автомобилю, которому нужен двигатель, дайте ему этот объект в качестве атрибута. Это называется композицией и обычно более гибко, чем глубокие цепочки наследования.

Полиморфизм

Полиморфизм означает, что разные объекты могут реагировать на один и тот же вызов метода по-своему. Вызывающему коду не обязательно знать точный тип:

class Square:
    def __init__(self, side):
        self.side = side
    def area(self):
        return self.side ** 2

class Circle:
    def __init__(self, radius):
        self.radius = radius
    def area(self):
        return round(3.14159 * self.radius ** 2, 2)

for shape in [Square(3), Circle(2)]:
    print(type(shape).__name__, shape.area())

# Square 9
# Circle 12.57

Эти два класса даже не имеют общего родителя. Python заботится только о том, чтобы у объекта был метод area — подход, известный как утиная типизация. Добавление Triangle позже не потребует никаких изменений в цикле.

Инкапсуляция и свойства

В Python нет по-настоящему частных атрибутов, вместо этого он опирается на соглашения. Одиночное подчеркивание, как в _price, сообщает другим разработчикам: «Это внутреннее, пожалуйста, не трогайте». Чтобы проверить значения, когда они установлены, используйте свойство, которое снаружи выглядит как простой атрибут:

class Product:
    def __init__(self, price):
        self.price = price

    @property
    def price(self):
        return self._price

    @price.setter
    def price(self, value):
        if value < 0:
            raise ValueError("price cannot be negative")
        self._price = value

p = Product(100)
p.price = 150
print(p.price)      # 150
p.price = -5        # ValueError: price cannot be negative

Это означает, что вы можете начать с простого атрибута и добавить проверку позже, не изменяя код, использующий этот класс. Поэтому не пишите методы get_price() и set_price() по привычке, как это можно сделать в Java. Синтаксис @ здесь представляет собой декоратор, который мы объясняем в Объяснения декораторов Python.

Методы класса и статические методы

class Temperature:
    def __init__(self, celsius):
        self.celsius = celsius

    @classmethod
    def from_fahrenheit(cls, f):
        return cls(round((f - 32) * 5 / 9, 1))

    @staticmethod
    def is_freezing(celsius):
        return celsius <= 0

Temperature.from_fahrenheit(212).celsius   # 100.0
Temperature.is_freezing(-3)                # True
Тип Первый аргумент Используйте его для
Метод экземпляра сам Работа с данными одного объекта
@classmethod клс Альтернативные конструкторы
@staticmethod Нет Помощники, связанные с классом

Классы данных

Когда класс в основном содержит данные, писать __init__, __repr__ и __eq__ вручную утомительно. @dataclass генерирует их из аннотаций типов:

from dataclasses import dataclass, field

@dataclass
class Item:
    name: str
    price: int
    tags: list = field(default_factory=list)

print(Item("Pen", 10))
print(Item("Pen", 10) == Item("Pen", 10))

# Item(name='Pen', price=10, tags=[])
# True

Совет: Не всему нужен класс. Если у нее нет состояния и есть только одно поведение, простая функция проще. Для простого поиска может быть достаточно словаря. Найдите класс, когда данные и правила, которые их защищают, явно принадлежат друг другу.

Распространенные ошибки

Использование изменяемого атрибута класса

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

class Cart:
    items = []            # shared by every cart!

    def add(self, item):
        self.items.append(item)

c1, c2 = Cart(), Cart()
c1.add("pen")
print(c2.items)

# ['pen']

Создайте его в __init__ с self.items = [], чтобы каждый объект получил свой собственный список.

Другие распространенные ошибки

  • Забываем self. Пишите self.balance, а не balance, внутри методов.
  • Забывание super().__init__(). Тогда ребенок пропускает атрибуты, установленные родителем.
  • Создание огромных классов. Класс, который делает все, сложно тестировать. Разделите это по ответственности.
  • Глубокое наследование. Двух уровней обычно достаточно, и композиция зачастую более ясна.
  • Не писать тесты. Классы с правилами легко тестировать, как показано в нашем руководстве по pytest с помощью небольшой тележки.

Итоги

Объектно-ориентированный Python сводится к группировке данных с использованием поведения, которое их защищает. Начните с __init__, методов и __str__, затем добавляйте наследование и свойства, когда вы столкнетесь с проблемой, которую они решают. В качестве следующего шага возьмите скрипт, который повсюду передает одни и те же переменные, и превратите их в один небольшой класс.

Часто задаваемые вопросы

В чем разница между классом и объектом?

Класс — это определение или план. Объект — это созданный из него конкретный экземпляр со своими собственными данными. Один класс может создавать множество объектов.

Что делает __init__ в Python?

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

Что такое self в Python?

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

Каковы четыре столпа ООП?

Это инкапсуляция, абстракция, наследование и полиморфизм. Вместе они помогают вам связывать данные с поведением, скрывать детали и повторно использовать код.

Когда мне следует использовать класс вместо функции?

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

Продолжайте учиться

Работайте с Stack Quora

Нужна помощь с тестированием, WordPress или SEO?

Мы помогаем командам выпускать лучшее программное обеспечение и развивать свои сайты. Расскажите нам, над чем вы работаете, и мы предложим четкий следующий шаг.

Продолжайте читать

Больше руководств по тестирование, искусственный интеллект и современные разработки

Понравилась эта статья? Выберите тему и сразу приступайте к нашим новейшим руководствам.

Искусственный интеллект

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

Галлюцинации ИИ объяснили: что это такое, почему языковые модели их создают, распространенные типы, как уменьшить их с помощью заземления и подсказо…

Читать статью →
DevOps

Объяснение переменных среды: файлы .env, секреты и правильно выполненная конфигурация

Переменные среды объясняются на примерах Python, которые мы запускали: их чтение и установка, почему каждое значение является строкой, файлы .env, н…

Читать статью →
Разработка ПО

Объяснение ограничения скорости API: алгоритмы, заголовки и обработка ошибок 429

Ограничение скорости API объясняется с помощью проведенного нами моделирования: сегмент токенов, фиксированное окно, скользящее окно, 429 ответов, з…

Читать статью →
Автоматизация тестирования

Издевательство в Python: unittest.mock, патч и ошибки, из-за которых тесты лгут

Издевательство на Python с помощью unittest.mock, протестировано: Mock и return_value, Side_effect, исправление использования имени, спецификация и …

Читать статью →
Тестирование ПО

Объяснение покрытия кода: покрытие линий или ветвей и что на самом деле означает 100%

Покрытие кода объяснено с помощью реального запуска покрытия.py: покрытие строк, ветвей и условий, чтение отчета, почему 100%-ное покрытие все еще м…

Читать статью →
Базы данных и SQL

DELETE, TRUNCATE и DROP в SQL: различия, откат и когда использовать каждый из них

Объяснение DELETE, TRUNCATE и DROP на примере протестированного SQL: что каждый из них удаляет, откат, триггеры, сброс идентификаторов, скорость и ч…

Читать статью →
Базы данных и SQL

Объяснение представлений SQL: создавайте, используйте и избегайте ловушек, с примерами

Представления SQL, объясненные с помощью запросов, которые мы выполняли: создание представления, результаты в реальном времени, скрытие столбцов, пр…

Читать статью →
Разработка ПО

Интерфейс TypeScript и тип: реальные различия, протестированные с помощью компилятора

Интерфейс TypeScript против типа, проверенный реальным компилятором: что могут делать оба, что может делать только один, слияние объявлений, расшире…

Читать статью →
Разработка ПО

Объяснение Python *args и **kwargs: гибкие функции с понятными примерами

Python *args и **kwargs, объясненные с помощью кода, который мы запускали: упаковка и распаковка, порядок параметров, аргументы только по ключевым с…

Читать статью →
Разработка ПО

Лямбда-функции Python: синтаксис, реальное использование и когда их не следует использовать

Лямбда-функции Python, объясненные с помощью кода, который мы запускали: синтаксис, сортировка с помощью ключа, карты и фильтра, замыкания, ловушка …

Читать статью →
Искусственный интеллект

Что такое ИИ-агенты? Как они работают: можно запустить простой цикл агента

Что такое агенты ИИ? Простое руководство по циклу агента, инструментам, памяти и ограничениям, с небольшим циклом Python, который мы запустили, реал…

Читать статью →
DevOps

Мониторинг и наблюдаемость: реальная разница с журналами, метриками и трассировками

Объяснение мониторинга и наблюдаемости: известные и неизвестные сбои, журналы, метрики и трассировки, пошаговое руководство по инцидентам при оформл…

Читать статью →
DevOps

Docker Volumes против Bind Mounts: правильное сохранение данных контейнера

Объяснение томов Docker и монтирования привязки: почему исчезают данные контейнера, именованные тома, монтирование привязки, tmpfs, примеры создания…

Читать статью →
Автоматизация тестирования

TDD против BDD: ключевые различия, одна функция, созданная для обоих способов, и когда использовать каждый

TDD и BDD объясняются с помощью одной функции скидки, созданной в обоих направлениях: красно-зеленый рефакторинг с кодом, который мы запускали, сцен…

Читать статью →
Тестирование ПО

Пользовательское приемочное тестирование (UAT): процесс, контрольный список и реальные примеры

Приемочное тестирование пользователей объяснило: кто его проводит, чем оно отличается от контроля качества, семиэтапный процесс, шаблон тестового сц…

Читать статью →
Базы данных и SQL

Объяснение значений NULL в SQL: IS NULL, COALESCE, NULLIF и ловушки, которых следует избегать

Значения SQL NULL объяснены с помощью запросов, которые мы выполнили: трехзначная логика, IS NULL, COALESCE, NULLIF, как агрегаты, соединения и сорт…

Читать статью →
Базы данных и SQL

Оператор SQL CASE WHEN: синтаксис, реальные примеры и распространенные ошибки

SQL CASE WHEN объяснен с помощью запросов, которые мы выполняли: простые формы и формы для поиска, порядок условий, повороты с помощью SUM, трюки CO…

Читать статью →
Разработка ПО

Что такое JWT? Веб-токены JSON, объясненные на рабочем примере

Что такое JWT? Объяснение JSON Web Tokens: три части: токен, созданный и измененный в коде, который мы запускали, JWT и сеансы, хранилище, токены об…

Читать статью →
Разработка ПО

Объяснение цикла событий JavaScript: стек вызовов, микрозадачи и таймеры с примерами

Цикл событий JavaScript объясняется с помощью кода, который мы запускали: стек вызовов, очереди задач и микрозадач, почему setTimeout 0 не является …

Читать статью →
Разработка ПО

Генераторы Python и объяснение доходности: экономьте память с помощью реальных примеров

Генераторы Python и доходность, объясненные с помощью кода, который мы запускали: как они приостанавливаются и возобновляются, измеряют экономию пам…

Читать статью →
Искусственный интеллект

Что такое вложения? Простое объяснение векторов и косинусного сходства

Что такое вложения? Простое руководство по векторам, косинусному подобию и семантическому поиску с небольшим примером, который мы использовали, общи…

Читать статью →
DevOps

Сине-зеленое и канареечное развертывание: различия, компромиссы и как выбрать

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

Читать статью →
Автоматизация тестирования

Ненадежные тесты: что их вызывает и как их исправить навсегда

Ненадежные тесты объясняются на демонстрациях, которые мы запускали: основные причины, способы подтверждения и диагностики, правильные исправления в…

Читать статью →
Тестирование ПО

Нагрузочное тестирование и стресс-тестирование: различия, метрики и примеры k6

Объяснение нагрузочного и стресс-тестирования: что доказывает каждое из них, тесты на всплески и выдержки, важные метрики, почему средние значения в…

Читать статью →
Тестирование ПО

Тестовый пример и тестовый сценарий: ключевые различия, примеры и когда использовать каждый

Объяснение тестового случая и тестового сценария: четкие определения, параллельная таблица, одна функция сброса пароля, взятая из сценариев в случаи…

Читать статью →
Базы данных и SQL

Оптимизация SQL-запросов: чтение планов выполнения и исправление медленных запросов с указанием времени

Оптимизация SQL-запросов проверена на миллионе строк: читайте планы выполнения, добавляйте правильные индексы, исправляйте неразмещаемые фильтры, ис…

Читать статью →
Базы данных и SQL

SQL UNION против UNION ALL: различия, примеры и проверка производительности

SQL UNION и UNION ALL объяснены с помощью запросов, которые мы выполнили: дубликаты, правила, которым следуют оба, реальная ошибка данных, измеренна…

Читать статью →
Разработка ПО

Учебное пособие по API JavaScript Fetch: GET, POST, обработка ошибок и тайм-ауты

Учебное пособие по API JavaScript Fetch, протестированное на локальном сервере: GET и POST, почему не выдается ошибка 404, многоразовый помощник, ст…

Читать статью →
Разработка ПО

Обработка файлов Python: чтение, запись, CSV, JSON и pathlib с примерами

Обработка файлов Python объясняется с помощью кода, который мы запускали: открытые режимы, чтение больших файлов, CSV, JSON, pathlib, двоичные файлы…

Читать статью →
Разработка ПО

Классы и объекты Python: учебник ООП с реальными примерами

Классы и объекты Python, объясненные с помощью кода, который мы запускали: __init__, методы, атрибуты класса и экземпляра, наследование, свойства, м…

Читать статью →
Искусственный интеллект

Что такое большая языковая модель? Как работают LLM, объяснено без шумихи

Что такое большая языковая модель? LLM объясняется простым языком: токены, встраивания, внимание, обучение, температурные и контекстные окна, крошеч…

Читать статью →
DevOps

Команды Linux для начинающих: основное руководство по терминалу с примерами

Команды Linux для начинающих, сгруппированные по задачам: навигация, файлы, просмотр журналов, grep, каналы, разрешения, процессы и архивы, с практи…

Читать статью →
Автоматизация тестирования

Selenium vs Playwright: ключевые различия, сравнение кода и что выбрать

Сравнение Selenium и Playwright: архитектура, ожидание, поддержка браузера и языка, отладка, одинаковый тест в обоих инструментах, советы по миграци…

Читать статью →
Тестирование ПО

Разделение эквивалентности: метод проектирования тестов, объясненный на рабочих примерах

Объяснение эквивалентного разделения: как найти действительные и недействительные разделы, рабочие примеры для возрастов, паролей и купонов, проведе…

Читать статью →
Тестирование ПО

Серьезность и приоритет в тестировании программного обеспечения: различия, матрица и реальные примеры

Объяснение серьезности и приоритета при тестировании программного обеспечения: четкие определения, четырехсторонняя матрица с примерами, шкалы уровн…

Читать статью →
Базы данных и SQL

Учебное пособие по подзапросам SQL: типы, коррелирующие подзапросы и EXISTS с примерами

Руководство по подзапросам SQL с выполненными нами запросами: скалярные подзапросы, IN, FROM и SELECT, коррелированные подзапросы, EXISTS, ловушка N…

Читать статью →
Базы данных и SQL

Объяснение транзакций SQL и ACID: COMMIT, ROLLBACK и уровни изоляции

Транзакции SQL и ACID, объясненные с помощью банковского перевода, который мы выполнили: COMMIT, ROLLBACK, точки сохранения, блокировки, уровни изол…

Читать статью →
Разработка ПО

Git merge vs rebase: отличия, примеры и когда что использовать

Git merge vs rebase с реальным выводом log, сравнительной таблицей, золотым правилом rebase и безопасным рабочим процессом для команды.

Читать статью →
Разработка ПО

Генераторы списков в Python: синтаксис, примеры и когда их избегать

Генераторы списков в Python: синтаксис, фильтры, if-else, вложенные циклы, измеренное время и случаи, когда обычный цикл for лучше.

Читать статью →
Базы данных и SQL

SQL JOIN: объяснение с примерами (Inner, Left, Right, Full)

Разберите SQL JOIN шаг за шагом на примерах таблиц и запросов: INNER, LEFT, RIGHT, FULL, CROSS и SELF, а также частые ошибки и советы по производите…

Читать статью →