Итак, вы познакомились с объектно-ориентированным образом мышления и хорошо понимаете разницу между классом и объектом, а также между интерфейсом и реализацией. Теперь давайте внимательно познакомимся с принципами и парадигмой объектно-ориентированного программирования. Вы уже знаете, что существует три основных парадигмы ООП. Это парадигмы — наследование, инкапсуляция и полиморфизм. Давайте коротко рассмотрим каждую из них. Наследование — это один из основных механизмов ООП, оно позволяет создавать сложные системы классов. Основными понятиями в наследовании являются "родительский класс" и "класс-потомок". Класс-потомок наследует все публичные методы и переменные класс-родителя. Это позволяет строить сложные иерархии классов. На принципе наследования построены многие паттерны проектирования, о которых пойдет речь в следующих двух неделях курса. Полиморфизм тесно связан с наследованием, а еще с интерфейсом и реализацией, о которых я говорил в предыдущем видео. Этот принцип позволяет использовать один и тот же код для работы с различными объектами, имеющими одинаковый интерфейс, но обладающими различной реализацией. Такая ситуация как раз часто возникает при наследовании. Мы можем работать с классами-потомками также, как работали бы с родительским классом. С наследованием и полиморфизмом мы довольно подробно познакомимся в следующем уроке, а сейчас давайте поговорим про такую парадигму как инкапсуляция. Пусть у нас имеется какой-то объект, который мы хотели бы описать. В процедурном программировании мы могли бы создать большое количество переменных и функций, которые эти переменные обрабатывают. В объектно-ориентированном программировании мы поступаем по-другому: мы оперируем такими понятиями как класс и объект. Довольно естественно в таком случае было бы упаковать все наши функции и переменные в некоторый единый компонент — в этом и заключается инкапсуляция. Есть расхожее мнение, что в Python инкапсуляции нет. Вообще нет. Однако, на самом деле, это утверждение абсолютно неверное инкапсуляция в Python присутствует в полной мере, почти. Часто под инкапсуляцией понимается возможность сокрытия данных некоторой системы от пользователя. Скрытые методы будут доступны только самому экземпляру класса. Но зачем одному программисту может потребоваться скрывать что-то от другого? Тем более, если копнуть глубже, то объект при работе хранится в памяти, а значит, если очень захочется, то доступ к нему все равно можно получить. Сокрытие данных позволяет, во-первых, построить удобный и простой интерфейс некоторого класса, во-вторых, упростить его реализацию. Разберем первый случай. Пусть в вашем классе реализован некоторый служебный метод. Этот метод необходим для работы вашей системы, но пользователю он абсолютно бесполезен — тогда вы можете скрыть этот метод от пользователя, сделав его приватным. Второй случай более наглядный. Пусть вы описываете класс "Котик". У котика среди атрибутов наверняка есть возраст и вес. Давайте представим, что эти поля являются публичными, и любой желающий может прийти и в любой момент изменить их. Ваш класс используется какой-то системой. В этой системе, по недосмотру или специально, нет проверки входных данных, и поэтому любому из этих атрибутов можно присвоить отрицательное значение. Но ведь это абсолютно не имеет смысла! Однако можно сделать атрибут приватным, а доступ к нему осуществлять только с использованием специальных методов, называемых "геттер" и "сеттер". Геттер — возвращает значение атрибута, а сеттер может устанавливать это значение. При этом в сеттер могут быть встроены все необходимые проверки на корректность входных данных. Давайте вспомним, как устроено псевдосокрытие данных в языке Python. Перед полями, которые мы хотим сделать приватными, просто следует поставить два символа нижних подчеркивания. Но что будет, если мы попытаемся прочитать такое поле у экземпляра класса? Python выдаст ошибку. То есть сокрытие данных все-таки работает и мы зря паникуем. На самом деле — нет. Просто Python автоматически переименовывает такие поля по определенным правилам. Получить доступ к ним можно, если запросить поле с именем "нижнее подчеркивание, название класса и далее название приватного поля с двумя символами нижнего подчеркивания вначале". Во многих других объектно-ориентированных языках приватные поля не наследуются, и, по идее, такое поведение правильное с точки зрения объектно-ориентированного программирования, но из-за механизма переименования переменных и так как действительно приватных полей в Python не существует, все переменные будут отнаследованы. Эту особенность стоит учитывать, когда вы пишете объектно-ориентированные программы на языке Python. Также не следует забывать, что это всего лишь особенность языка, и такое поведение, с точки зрения ООП, вообще говоря, некорректно. Кроме трех основных парадигм, к парадигмам ООП часто относят абстракцию. Она говорит, что в коде мы описываем всего лишь некоторую модель объекта. Эта модель объекта обязана содержать все ключевые характеристики моделируемого объекта, но при этом не должна содержать лишней информации. И все-таки абстракцию нельзя с чистой совестью отнести к парадигмам программирования. Она является скорее принципом, по которому строится хороший объектно-ориентированный код. В языке Python нет специальных механизмов, позволяющих реализовать принцип абстракции — эта задача полностью ложится на плечи разработчика. Кроме того, выполнение этого принципа носит скорее рекомендательный характер. Да и вообще, кто знает, какие из свойств объекта будут важными для пользователя вашей системы, а какие не будут? Итак, мы поговорили про парадигмы ООП в языке Python. В следующем видео вы узнаете о SOLID принципах объектно-ориентированного программирования.