Holy Python
497 subscribers
28 links
Станьте "папой" питона!
Download Telegram
Channel created
#ООП

Введение

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

Что это такое и зачем мне это нужно?

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

Структура ООП

Вся программа, которая придерживается данной методологии, содержит в себе набор классов и объектов.

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

Объект - является экземпляром класса.

Немного истории

Корни императивного и функционального программирования лежат в формальной математике вычислений, они появились намного раньше цифровых компьютеров.
ООП создателем которого является Алан Кей пришло намного позже, оно является началом революции в структурном программировании, так как оно на новом уровне решало основную задачу структурного программирования:

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

Первый известный объект был использован Айвеном Сазерлендом в его приложении Sketchpad.
Объекты представляли собой графические знаки, выводимые на экране осциллографа,
и поддерживающие наследование через динамических делегатов,
которые Айвен Сазерленд назвал в своей работе «мастер-объектами» (masters).
Любой объект мог стать мастер-объектом, дополнительные экземпляры объекта были названы «реализациями» (occurrences).
В следующих постах мы разберём эту программу более подробно.

Первым ОО языком программирования, был Simula, спецификации которого были разработаны в 1965 году.

Затронем парадигмы

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

Дополнительные материалы

ООП, Википедия: https://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BD%D0%BE-%D0%BE%D1%80%D0%B8%D0%B5%D0%BD%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5
Алан Кей, Википедия: https://ru.wikipedia.org/wiki/%D0%9A%D1%8D%D0%B9,_%D0%90%D0%BB%D0%B0%D0%BD_%D0%9A%D1%91%D1%80%D1%82%D0%B8%D1%81
👍13
#ООП

Введение

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

Класс

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

Метод в ООП, это любая функция, принадлижащая к классу или объекту, которая имеет ссылку на конкретный экземпляр класса.
В питоне первый аргумент метода обязан быть этой ссылкой, по соглашению его называют self, но это не зарезервированое слово. В других языках программирования нет такого 'обязательного self',
т.е. передавать ссылку на конкретный объект не нужно. Спрашивается: Тогда почему в питоне так сделали?
Ответ вы можете найти сами просто написав и запустив программу, содержащую всего одну строку: 'import this'.
👍9
#ООП

Введение

Продолжая тему ООП. Сегодня мы поговорим о парадигмах ООП. Для начала, давайте вспомним что такое парадигма:

Парадигма - это совокупность идей и понятий, определяющих стиль написания компьютерных программ.

Сколько парадигм в ООП?

Над количеством парадигм в данной методологии ведутся активные споры. Для данной серии постов мы будем считать что есть всего 4 парадигмы.

4 кита ООП

1. Наследование
2. Инкапсуляция
3. Полиморфизм
4. Абстракция

Вот они, 4 парадигмы ООП, на которых строиться вся методология. Именно в этом порядке в следующих постах мы разберём каждую из них.
👍11
#ООП


Введение

Сегодня мы поговорим о первой из четырёх парадигм ООП, наследовании.
Рассмотрим каким оно должно было быть и какое мы получили в большинстве сегодняшних
языках программирования.

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

Наследование – это свойство системы, позволяющее описать новый класс на основе уже существующего с частично или полностью заимствующейся функциональностью.
Класс, от которого производится наследование, называется базовым, родительским или суперклассом.
Новый класс – потомком, наследником или производным классом.
Для того чтобы понять как работает наследование, нам нужно перенестись в реальный мир.
Представим вы повар-технолог в пиццерии, в вашей пиццерии готовят вкусную сырную пиццу.
Но времена меняются и сырная пицца всем приелась, тогда вам поручили задание создать новый вид пиццы.
Очевидно, что вы не будете с нуля создавать новую рецептуру пиццы, вы возьмёте старую сырную пиццу и добавите в неё томатов.
Только что вы применили наследование.

Каким должно было быть наследование?

Помните Айвена Сазерленда? Да-да, того самого, который создал приложение Sketchpad и использовал в нём первый известный объект.
Объекты представляли собой графические знаки, выводимые на экране осциллографа, и поддерживающие наследование через динамических делегатов,
которые он назвал в своей работе «мастер-объектами» (masters).
Любой объект мог стать мастер-объектом, дополнительные экземпляры объекта были названы «реализациями» (occurrences).

Да, именно наследование, правда тогда это было правильное(Именно такое наследование хотел видеть Алан Кей) наследование, которое называется прототипное наследование.

Прототипное наследование vs Классическое наследование(наследование которое мы имеем)

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

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

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

Дополнительные материалы


https://bit.ly/3Pobuv7
https://habr.com/ru/company/hexlet/blog/303754/
https://bit.ly/3NepPZ8
2👍2🥰1
#ООП

Введение

Продолжая тему ООП. Сегодня мы рассмотрим вторую, самую сложную парадигму в данной методологии - инкапсуляцию.

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

Вопрос: Почему же она самая сложная?

Ответ:

1. ИМХО В разных языках её можно определить по разному.
2. Есть достаточное количество неверных определений данной парадигмы.

Вот правильное определение инкапсуляции в питоне:

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

Инкапсуляция как объединение

Пусть мы создали класс User. В нём мы создали поле name. Затем мы создали метод get_username, который возвращает значение поля name:


class User:
name = 'Mark'

def get_name(self) -> str:,
return self.name


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

Про уровни доступа

Модификаторы доступа — это чаще всего ключевые слова, которые регулируют уровень доступа к разным частям твоего кода.

В питоне в отличие от Java, C++ и многих других языков программирования, не существует уровней и модификаторов доступа вообще. А то что называют уровнями доступа в питоне - механизм и соглашение не совсем относящиеся к этой теме. Об этом механизме и соглашение мы поговорим ниже.

Атрибуты для "внутреннего использования"

Су
ществует соглашение, что атрибуты, классы, методы и другие программные члены с одним подчёркиванием _ перед названием, из вне трогать не стоит, так как они предназначены для "внутреннего использования в классе" и они не являются частью API класса или модуля. Это соглашение никак не закреплено механизмами языка => программист если захочет может спокойно его нарушить. Данное соглашение позволяет условно разделить API класса и его внутренности.

name mangling

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

Чтобы использовать name mangling в питоне нужно поставить два подчеркивания перед именем атрибута.

При попытке получить доступ к защищённому нейм манглингом атрибуту вы получите ошибку.

Очевидно данный механизм тоже можно обойти.

Как обойти name mangling?

Питон предоставляет специальный синтаксис для обхода данного механизма.

Если мы хотим обойти name mangling атрибута:

ИмяКласса._ИмяКласса__атрибут

Ес
ли мы хотим обойти name mangling метода:

объект._ИмяКласса__метод

Итоги

1. Управление доступом, никак не относится к инкапсуляции. Инкапсуляция это в первую очередь объединение данных и методов в единый компонент.

2. В питоне не существует никаких уровней и модификаторов доступа, а то что ими называют - механизмы и соглашения не относящиеся к этой теме.

3. Если вы хотите условно разделить публичное API и внутренности класса, то можно использовать соглашение о подчёркивание перед именем. Если же вы хотите чётко(так чтобы клиент не имел доступа к внутренностям) разделить публичное API и внутренности класса, то могу вам порекомендовать паттерн проектирования "Фасад".

4. Если вам нужно защитить атрибут от доступа из вне или переопределения, то можете использовать механизм name mangling.
👍2
#ООП

Введение

Продолжая тему ООП. Сегодня мы рассмотрим третью парадигму в данной методологии - полиморфизм.

Полиморфизм

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

Всего существует три вида полиморфизма:

1. Полиморфизм подтипов
2. Параметрический полиморфизм
3. Ad-hoc полиморфизм

Полиморфизм подтипов

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

Возможно это прозвучало сложно, однако полиморфизм проще понять на практике, поэтому давайте рассмотрим пример.

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

class Test1:
def do(self):
print(1)

class Test2:
def do(self):
print(2)

test1 = Test1()
test2 = Test2()

for _ in (test1, test2):
_.do()


Вывод:


1
2


Мы создали два очень похожих класса, которые имеют методы с одинаковым названием. А затем просто прошлись циклом по кортежу из экземпляров этих классов и вызвали метод do используя общую переменную "_" .
Мы никак не связывали их одним родителем и не соединили классы каким-либо другим способом. Это и есть проявление полиморфизма подтипов.

Параметрический полиморфизм

Параметрический полиморфизм в языках программирования и теории типов — свойство семантики системы типов, позволяющее обрабатывать значения разных типов идентичным образом, то есть исполнять физически один и тот же код для данных разных типов

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

Ad-hoc полиморфизм

Ad-hoc полиморфизм в питоне выражается ввиде перегрузки операторов.

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

Пример перегрузке оператора:

Пусть мы создали объект Date с полем day. Теперь нам нужно сделать так, чтобы мы могли использовать оператор "+" к этому объекту и изменять поле day на прибавленное число.
Чтобы это сделать, нам нужно перегрузить оператор сложения, для этого в классе Date нужно создать магический(специальный) метод add.

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

Дополнительные материалы

https://bit.ly/3zdXWfX
https://bit.ly/38IM9vv
https://bit.ly/3Tpo4MA
4👍2
#ООП

Введение

Продолжая тему ООП. Сегодня мы рассмотрим четвёртую парадигму в данной методологии - абстракцию.

Абстракция

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

Любой объект в реальном мире это абстракция. Когда мы говорим "клавиатура", мы не объясняем, что это объект состоящий из несколько видов пластика и
лампочек для подсветки.

Если говорить о примере абстракции в программирование, то давайте представим, что вы хотите
отправить http запрос, вы можете просто взять готовую библиотеку requests и получить высокоуровневый интерфейс,
который является абстракцией над HTTP протоколом и сетевым взаимодействием.

Как достичь абстракции в питоне?

Для достижения абстракции в питоне, вам потребуется библиотека abc(Abstract Base Classes), позволяющая
создавать абстрактные классы(если вы пришли в питон с другого языка, то могу сказать, что абстрактный класс очень похож на интерфейс).

Абстрактный класс

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

Абстрактный метод - это метод, который обязан реализовать потомок абстрактного класса.

Грубо говоря абстрактный класс - это класс скелет на основе которого вы описываете, его потомков.

Дополнительные материалы

https://bit.ly/3x1IEs5
https://bit.ly/3wZeq93
https://bit.ly/3tcoLh0
👍10
#тайпхинты

Введение

Немного отвлечёмся от ООП и рассмотрим очень важную тему в питоне - тайпхинты.

Типизация

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

Тайпхинты

На помощь приходят, тайпхинты! Python сохранил идею динамической, утиной типизации и с версии Python 3.6 начал поддерживать тайпхинты.

Тайпхинт, по своей сущности похож на комментарий, ведь интерпретатор никак не учитывает его. Кроме того, что тайпхинты помогают читать код, также их учитывают популярные IDE и линтеры.

Синтаксис тайпхинтов

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

Подсказка типа для аргумента, переменной и атрибута имеет такой синтаксис:


название: тип


Примеры:

test: int = 4

self.test: int = 4

def x(test: int):



Подсказка типа
для возвращаемого значения функции имеет такой синтаксис:



def название(...) -> тип:


Пример:


def test(...) -> int:

Дополнительные материалы

https://habr.com/ru/company/lamoda/blog/432656/
https://www.python.org/dev/peps/pep-3107/
https://www.python.org/dev/peps/pep-0526/
👍2
#тайпхинты

Введение

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

List, Tuple и Dict

Вы конечно можете использовать встроенные в питон типы list и tuple, однако, данные тайпхинты из пакета typing позволяют уточнить какие элементы хранятся в структуре.

Примеры:

List[int]
Tuple[int]
Dict[int, int]

Any

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

Union

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

Пример:

Union[int, str]

UPD: в питоне 3.10 Union стал ненужным, так как появилась такая конструкция: int | str, которая делает тоже самое, что и этот тайпхинт!

Optional

Optional - это тоже самое, что и Union[..., None] или ... | None.

С помощью Optional вы можете указать, что вы хотите, чтобы использовался не только указаный тип, но и None.

Пример:

Optional[int] # int | None

NoReturn

NoReturn нужен, когда функция никогда не возвращает управление.

Примеры:

def test() -> NoReturn:
sys.exit()


def test() -> NoReturn:
while True:
pass


Iterable

Если функция является генераторной и содержит yield, нужно использовать тайпхинт Iterable.

Пример:

def test() -> Iterable[int]:
yield 3
yield 4


Дополнительные материалы

https://docs.python.org/3/library/typing.html
🔥5👍1
#py2exe #pyinstsller #ошибки

Введение

Сегодня, я хотел бы разобрать такую библиотеку как pyinstaller, которая позволяет собирать python в exe.

Вопрос: "Почему я решил сделать этот пост?"
Ответ: "В последнее время, я заметил тенденцию того, что новички начали очень часто использовать pyinstaller для сборки exe, хотя данный инструмент несёт в себе только вред."

Процесс сборки exe

Как pyinstaller собирает exe(что-то похожее на него):,

Шаг 1: Считывает код файла
Шаг 2: Анализирует код, для получение всех зависимостей необходимых для работы
Шаг 3: Создаёт .spec файл конфигурации
Шаг 4: Собирает все файлы и добавляет к ним интерпретатор питона.
Шаг 5: Создаёт папку BUILD, куда записывает логи и рабочие файлы
Шаг 6: Создаёт папку DIST
Шаг 7: Записывает все необходимые файлы в одну папку или что-то похожее на exe.

Почему же он вреден?

1. Вес exe огромен
2. Это подобее exe пытается запустить то, что считало из себя, что может напоминать поведение троянов и как следствие вызывать подозрения у антивирусов
3. Если вы использовали флаг --onefile, то exe начинает очень сильно засорять парку tmp
4. Код никак не защищается(как думают многие не опытные программисты, для обфускации кода используйте pyarmor), даже если вы собирали pyc, а не py.
5. Огромное количество библиотек не работают в exe собранном данной библиотекой.
6. При сборке под линукс возникают проблемы с работой стандартной библиотеки.

Выводы

Pyinstaller - очень похож на обычный архиватор, который просто засовывает в исполняемый файл интерпретатор питона. Это самый плохой способ распространения программ на питоне.
👍12
#SOLID

Введение

Сегодня мы начнём очень важную и сложную тему в программировании - SOLID.

Что это такое и зачем это нужно?

SOLID - это 5 основных принципов ООП, предложенных Робертом Мартином, при соблюдении которых вы сможете без труда поддерживать и расширять вашу программу в течении долгого времени.

Расшифровка SOLID

S - single responsibility(принцип единой ответственности)
O - open-closed(принцип открытости закрытости)
L - Liskov substitution(принцип подстановки Барбары Лисков)
I - interface segregation(принцип разделения интерфейса)
D - dependency inversion(принцип инверсии зависимостей)

Дополнительные материалы

https://www.amazon.com/software-development-principles-razrabotka-printsipy/dp/5845905583
https://bit.ly/3NQQhs0
https://bit.ly/3auZM1D
👍5
#SOLID

Введение

Сегодня мы рассмотрим первый принцип SOLID - принцип единой ответственности.

Принцип единой ответственности

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

Грубо говоря, данный принцип гласит, что каждый объект должен выполнять только свою задачу. Например, если объект Dog, не должен реализовать что-то из кошки или вовсе быть кошкой.

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

Дополнительные материалы

https://bit.ly/3Q7ywqu
https://web-creator.ru/articles/solid_the_single_responsibility_principle
👍2
#SOLID #задача

Введение

Продолжая тему SOLID. Сегодня мы рассмотрим второй принцип SOLID - принцип открытости/закрытости.

Принцип открытости/закрытости

Принцип открытости/закрытости гласит: "Программные сущности должны быть открыты для расширения, но закрыты для модификации."

Грубо говоря, следование данному принципу заключается в том, что программное обеспечение изменяется не через изменение существующего кода, а через добавление нового кода.
То есть, новая функциональность должна добавлятся не модифицированием старого кода.

Задача

Пусть у нас есть класс Discount, который позволяет выдавать скидки в вашем интернет магазине:

class Discount:
def __init__(self, customer: str, price: int | float):
self.customer = customer
self.price = price

def give_discount(self) -> int | float:
if self.customer == 'fav':
return self.price * 0.2

После некоторого времени работы вашего магазина, вы создали VIP карту, которую получили постоянные клиенты, данная карта увеличивает скидку на 20%, а значит нужно создать ещё одно условие, для проверки имеет ли пользователь вип карту. А что будет когда у вас появится ещё больше разновидностей скидок? Правильно, вам придётся писать всё новые и новые условия.
Этот код - пример нарушения принципа открытости/закрытости. Попробуйте исправить данную программу.
👍1