Рубріки: Теория

Объекты и классы в Python: объясняем предельно просто

Сергей Почекутов

Суть объектно-ориентированного программирования (ООП) очевидно раскрывается в его названии. Эта парадигма предлагает представлять все компоненты программы как объекты из реальной жизни. У каждого такого объекта есть характеристики и он выполняет определенные функции.

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

Python — язык с удобной, продуманной объектной моделью. Поэтому использовать эту парадигму на нем приятно. Давайте познакомимся с основными понятиями ООП Python.

Если самостоятельно не получается освоить язык Python, то лучше поискать хорошие курсы. Мы можем посоветовать проверенные курсы от наших друзей школы Mate Academy, Powercode, Hillel.

1. Принципы ООП

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

Инкапсуляция

Инкапсуляция — это набор свойств и методов одного класса или объекта.

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

Чтобы управлять кодом было удобнее (и безопаснее), придумали инкапсуляцию. Это принцип, который призывает блокировать доступ к деталям сложных концепций.

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

Абстракция

Если вы пьете кофе, то есть большая вероятность, что вы использовали кофемашину.  Вы знаете, что кофемашина готовит кофе. Но вам не нужно знать, как она делает кофе. Все, что вам нужно знать, — какие кнопки нажимать, чтобы приготовить кофе. Вы используете интерфейс, определяемый кнопками, не беспокоясь о внутренней работе машины.

Рассматривайте метод как кофеварку, а ваш входной параметр — как кнопки на машине. Абстракция позволяет создавать бесшовные программы, просто зная, какой метод вызывать и какие параметры вводить.

Полиморфизм

Полиморфизм — способность одной функции выполняться по-разному. Это позволяет создавать несколько реализаций одной идеи. Например, вы делаете компьютерную игру. В ней есть класс «Транспорт» с методом «Двигаться». После выполнения метода самолет должен полететь, автомобиль — поехать, а корабль — поплыть. Все три действия — это движение, но реализованы они будут по-разному.

Полиморфизм можно применять двумя способами:

  • перегрузка метода (статический полиморфизм);
  • переопределение метода (динамический полиморфизм).

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

  • имеет разные параметры;
  • имеет разные типы возврата;
  • имеет разные модификаторы доступа.

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

  • имеет тот же список параметров;
  • имеет тот же тип возврата;
  • имеет модификатор доступа, более строгий, чем у родительского класса.

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

Наследование — возможность приобретать свойства существующих классов и создавать новые. Этот принцип призывает повторно использовать код без необходимости переписывать его в программе.

Вернемся к аналогии с компьютерной игрой. У вас есть абстракция «Транспорт». На этом уровне вы не учитывает характеристики каждого объекта: самолета, автомобиля, корабля.

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

Наследование позволяет сделать отдельный класс «Самолет», который будет наследником класса «Транспорт». Он сохраняет атрибуты класса «Транспорт» (год выпуска, цвет), но при этом получает новые — размах крыльев.

2. Класс

Объектно ориентированное программирование Python, как и других языков, основано на двух важных концепциях — классах и объектах.

Класс — это схема того, как что-то должно быть определено. На самом деле он не содержит никаких данных. Класс Cat указывает, что для определения кошки необходимы имя и возраст. Но он не содержит имя или возраст какой-либо конкретной кошки.

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

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

class FirstClass:

    pass

Для именования классов в Python используют нотацию CamelCase — каждое слово начинается с заглавной буквы.

В примере выше тело класса состоит из одного оператора pass. Он нужен для того, чтобы интерпретатор Python не выдавал ошибку. Фактически это пустой класс, у которого нет ни атрибутов (характеристик), ни методов. Давайте их добавим.

Добавление методов и атрибутов

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

Например, на основании класса Cat можно создать объекты c именами Milo и Simba, а также возрастом — 2 и 3 года.

Создание объектов рассмотрим чуть позже, а пока вернемся к конструкторам.

В Python конструктором является метод __init__(). В нем указываются все свойства, которыми должны обладать объекты класса Cat. Каждый раз, когда создается новый объект Cat, __init__() устанавливает начальное состояние, присваивая свойствам значения. То есть __init__() инициализирует каждый новый экземпляр класса.

Вы можете указать в __init__() любое количество параметров, но первым параметром всегда будет переменная с именем self. Когда создается новый экземпляр класса, он автоматически передается self параметру в __init__(), чтобы можно было определить новые атрибуты объекта.

Важно: self — не зарезервированное имя. У первого параметра при инициализации может быть и другое название. Однако есть соглашение, что его называют self. Это помогает унифицировать создание классов в разных проектах.

Пример:

class Cat:
    def __init__(self, name, age):
        self.name = name
        self.age = age

В теле __init__() есть два оператора, использующих переменную self:

  • self.name = name создает атрибут с именем name и присваивает ему значение параметра name.
  • self.age = age создает атрибут с именем age и присваивает ему значение параметра age.

Важно соблюдать отступы. Они показывают, что метод  __init__ принадлежит классу Cat, а атрибуты  self.name  и self.age принадлежат методу __init__.

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

Атрибуты, созданные в __init__(), называются атрибутами экземпляра. Их значения зависят от конкретного экземпляра класса. У всех объектов есть имя и возраст. Но значения атрибутов name и age будут различаться в зависимости от объекта.

Чтобы не запутаться, давайте посмотрим примеры. Вернемся к нашему классу Cat. Вот он:

class Cat:
    def __init__(self, name, age):
        self.name = name
        self.age = age

Создадим на его основе два объекта — экземпляра класса Cat. Первый объект — кошка Milo. Ей два года. Второй объект — кошка Simba, ей три года. У обоих объектов есть имя и возраст. Но значения у них разные. Это достигается благодаря ключевому слову self.

Self — указатель на текущий экземпляр класса. Он позволяет работать с отдельными объектами, а не всеми экземплярами, которые принадлежат классу. Благодаря self мы можем указать, что одну кошку зовут Milo, а вторую — Simba, что одной кошке — два года, а другой — три года.

Кроме атрибутов экземпляра существуют атрибуты класса. Они имеют одинаковое значение для всех объектов. Вы можете определить атрибут класса, присвоив значение имени переменной за пределами метода __init__().

Например:

class Cat:
    # Class attribute
    cute = "Cat is so cute"

    def __init__(self, name, age):
        self.name = name
        self.age = age

Атрибуты класса определяются под первой строкой имени класса и имеют отступ в четыре пробела. Им всегда должно быть присвоено начальное значение. При создании экземпляра класса автоматически создаются атрибуты класса, которым присваиваются их начальные значения.

Теперь вы можете создать двух кошек с разными именами и возрастом. Но их будет объединять атрибут класса cute — обе они милые. Этот атрибут класса будет появляться во всех экземплярах класса, которые вы будете создавать.

Важно:

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

Методы

Кроме __init__() могут быть и другие методы. Они делятся на три группы:

  • методы экземпляра класса;
  • методы класса;
  • статические методы.

Чтобы лучше понять разницу между ними, посмотрим пример:

class MyClass:
    def method(self):
        return 'instance method called', self
    @classmethod
    def classmethod(cls):
        return 'class method called', cls
    @staticmethod
    def staticmethod():
        return 'static method called'

В этом классе есть все три метода. Первый — метод экземпляра класса. Он принимает параметр self, но, как вы видели выше на примере атрибутов, ему можно передавать любые другие параметры.

Методы экземпляра класса — самые распространенные, обычно приходится работать именно с ними.

class Cat:
    def __init__(self, name, age):
        self.name = name
        self.age = age

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

Второй тип — метод класса. В примере выше он определен с помощью декоратора @classmethod. Декораторы — это обертки, которые позволяют менять назначение функций.

Методы класса принимают параметр cls. При вызове метода этот параметр указывает не на объект, а на сам класс. Такие методы не могут менять объекты по отдельности — как вы теперь знаете, для этого нужен параметр self. Но они могут менять состояние класса в целом, что влияет на все объекты этого класса.

Пример метода класса:

class Cat:
    def speak(cls):
        print('Мяу!')

Теперь вы можете создать экземпляры этого класса — конкретных кошек. Все они будут уметь говорить «Мяу».

Если вы измените метод класса, то это модифицирует всех кошек. Например:

class Cat:
    def speak(cls):
        print('Гав!')

Теперь все кошки будут лаять, а не мяукать. Пожалуй, лучше вернуть все как было.

Статический метод определен с помощью декоратора @staticmethod. Он принимает любые параметры в любых количествах, кроме self и cls. Статические методы не меняют состояние ни класса, ни объекта. Они помещаются в класс для того, чтобы быть в пространстве имен, их используют для организационных целей.

3. Объекты или экземпляры класса

Чем объекты отличаются от классов

В то время как класс является планом (схемой, чертежом — можно использовать разные сравнения), экземпляр представляет собой объект, созданный из класса и содержащий реальные данные. Экземпляр класса Cat — это уже не схема. Это настоящая кошка с именем и возрастом.

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

Как создать объект класса в Python

Сначала нужно создать класс. На его основе вы будете создавать объекты — разные экземпляры класса.

Допустим, есть класс Cat. В нем определены параметры, которые должны быть у каждого объекта этого класса.

class Cat:

cute = "Cat is so cute"
    def __init__(self, name, age):
        self.name = name
        self.age = age

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

milo = Cat("Milo", 2)
simba = Cat("Simba", 3)

Если в классе заданы параметры, а при создании объекта вы их не передаете, то вылезет ошибка. Например, вот этот код в данном случае не сработает:

milo = Cat()

В ответ появится сообщение об ошибке:

TypeError: __init__() missing 2 required positional arguments: 'name' and 'age'

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

Есть и неочевидный момент. Метод класса __init__() имеет три параметра. Почему же в примере ему передаются только два аргумента? Никакой магии нет. Когда вы создаете экземпляр объекта, Python создает новый объект и передает его первому параметру __init__(). Это по существу удаляет self, поэтому вам нужно беспокоиться только о параметрах name и age.

После создания экземпляров вы можете получить доступ к их атрибутам, используя запись через точку. Например:

milo.name
Output:
“Milo”

simba.age
Output:
3

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

milo.cute
Output:
"Cat is so cute"

Одним из самых больших преимуществ использования классов для организации данных является предсказуемость. Все экземпляры класса Cat имеют атрибуты .cute, .name .age, поэтому вы можете уверенно их использовать, зная, что они всегда будут возвращать значение.

При этом атрибуты можно менять динамически. Например:

milo.age = 4
    milo.age
    Output:
    4

Ключевым выводом здесь является то, что пользовательские объекты по умолчанию изменяемы.

Заключение

Мы рассмотрели основы объектно-ориентированного программирования в Python. Теперь вы знаете основные принципы и умеете создавать классы и объекты. Чтобы закрепить знания, посмотрите это видео про объектно-ориентированное программирование:

Останні статті

Обучение Power BI – какие онлайн курсы аналитики выбрать

Сегодня мы поговорим о том, как выбрать лучшие курсы Power BI в Украине, особенно для…

13.01.2024

Work.ua назвал самые конкурентные вакансии в IТ за 2023 год

В 2023 году во всех крупнейших регионах конкуренция за вакансию выросла на 5–12%. Не исключением…

08.12.2023

Украинская IT-рекрутерка создала бесплатный трекер поиска работы

Unicorn Hunter/Talent Manager Лина Калиш создала бесплатный трекер поиска работы в Notion, систематизирующий все этапы…

07.12.2023

Mate academy отправит работников в 10-дневный оплачиваемый отпуск

Edtech-стартап Mate academy принял решение отправить своих работников в десятидневный отпуск – с 25 декабря…

07.12.2023

Переписки, фото, история браузера: киевский программист зарабатывал на шпионаже

Служба безопасности Украины задержала в Киеве 46-летнего программиста, который за деньги устанавливал шпионские программы и…

07.12.2023

Как вырасти до сеньйора? Девелопер создал популярную подборку на Github

IT-специалист Джордан Катлер создал и выложил на Github подборку разнообразных ресурсов, которые помогут достичь уровня…

07.12.2023