CoolPython
4.64K subscribers
20 photos
44 links
Канал об основах Python и хороших практиках разработки. Создаём системность в обрывочных знаниях.

Тем, кто хочет понимать, что пишет!
Download Telegram
Материалы

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

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

🐟Базовый курс по Python (циклы, словари/строки/списки и прочие основы языка) есть на Stepik.

🐟Еще есть хорошая специализация на Coursera. Сначала основы языка, потом более продвинуто: детали, ООП на Python, тестирование, многопоточность, асинхронность и веб-программирование. Мне нравится, что все подробно, с примерами, с задачами на грейдере и близко к реальному миру.

🐟Дока к языку — это must. Можно начать с PEP8, PEP20 и FAQ.

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

🐟Часто рекомендуют Лутца <<Изучаем Python>> в двух томах, но я его не очень люблю. Есть такой буддистский коан, в котором учитель льет чай в чашку ученика, пока чай не начинает литься через край. Так же происходит, когда мы пытаемся слишком быстро что-то усвоить и в действительности материал не укладывается в голове. ИМХО, сложность в Лутце растет слишком быстро, но если это и в кайф, то вперед.

🐟В Питере, на моей исторической родине, есть Computer Science Center. Это что-то вроде независимой магистратуры, где читают курсы по программированию и открытые тематические лекции. У них есть бомбический канал на YouTube, где можно заценить уровень ребят. Очень советую этот курс по Python за глубину и хорошую проработку материала. На канале есть и другие курсы.

🐟Если хотите с головой окунуться в многопоточность, асинхронность и разобраться, что такое GIL, есть великолепные доклады с ливкодингом от гуру Python Дэвида Бизли.

🐟И если все еще не хватает хардкора, то Филип Гуо на протяжении 10 лекций разбирается в исходниках CPython. Это прям самое крутое из того, что находила в последнее время.

Не то чтобы это был необходимый запас для разработки, но если начал рекомендовать курсы, становится трудно остановиться. Еще есть алгоритмы (1, 2), основы линукса (1, 2), bash, сетей, git и баз данных(1, 2). Можно дополнить пет-проектом и наскребете аналог одного-двух лет бакалавриата по специальности.

А еще всегда можно оставаться на канале Python in depth, я здесь говорю о простых и сложных штуках. Если есть еще какие-нибудь запросы или можете чем-нибудь дополнить мой список, пишите в фидбэк, обсудим.

PS: Кстати, о Coursera. Если курс покупать не хочется или нет возможности, то многие курсы там можно пройти в режиме слушателя. Обычно это означает доступ ко всем видео и некоторым задачам, но сертификат получить будет нельзя. Если ситуация с деньгами сложная, а сертификат хочется, то можно написать письмо (загуглите, как это сделать), чтобы курс открыли бесплатно. Обычно Coursera лояльны в этом отношении и с высокой вероятностью идут навстречу.

Учитесь и берегите себя! Всем классной, вашей, продуктивной недели. 🐠

#лекции #курсы #век_живи #основы
👍2🔥1
Грусти пост о формулах в коде

Подсмотрела, как коллеги, которые пишут на C++, оформляют формулы. Здесь закомментировали черту и разбили ей формулу геометрической прогрессии на числитель и знаменатель. Получилась очень читаемо, а еще функция документирует себя сама!
 
//Sum of first n terms of a geometric series.
// S = a + ar + ar^2 + ... + ar^n

float geom_sum(int n, float a, float r)
{
return
(a*(1 - pow(r, n + 1)))
/ //-----------------------
(1 - r);
}


Мне этот стиль очень нравится, но жаль, что интерпретатор так не позволяет писать в исполняемом коде. По крайней мере, у меня не получилось сделать, чтобы похожее форматирование заработало. Поэтому в теле функции я обычно пишу числитель и знаменатель отдельно, чтобы не было очень длинно, а выражение в docstring'е оформляю именно так. На Python получается что-то вроде:
 
def geom_sum(n, a, r):
"""
Sum of first n terms of a geometric series.
S = a + ar + ar^2 + ... + ar^n

1 - pow(r, n + 1)
S = a -----------------
1 - r

:param n: Number of terms
:param a: First term
:param r: Common ratio, r < 1
:return: Sum of series
"""

num = a*(1 - pow(r, n + 1))
denom = 1 - r
return num/denom


Не стала обрабатывать случай расхождения ряда, я сейчас не об этом. А так хорошо бы. Такие дела! 🐠

#кодстайл #докстринг #формулы #комментарии #вообще_другой_язык #cpp
👍1
​​Введение в декораторы

В нескольких следующих постах я хочу поговорить о декораторах. Будет базовое определение, мотивация их использовать, всякие хитрости, а еще куча примеров.

Прежде, чем говорить о декораторах, нужно кое- что узнать о функциях в Python. Допустим, у нас есть функция, которая здоровается с Юпи:

def hey_Jupi():
print("Привет, Юпи!")

Функции в Python -- это объекты первого класса, ничем не хуже, чем int'ы или словари. Это значит, что:

🐙 Функцию можно присвоить переменной:

say_hi = hey_Jupi
say_hi()
# Привет, Юпи!

🐙 Функцию можно вернуть из функции:

def wrapper(func):
print("Юпи пришла.")
return func

hello_Jupi = wrapper(hey_Jupi)
# Юпи пришла.
hello_Jupi()
# Привет, Юпи!

🐙 Функцию можно определить внутри другой функции:

def deco(func):
def wrapper():
print("Юпи пришла.")
func()
return wrapper

hey_Jupi = deco(hey_Jupi)
hey_Jupi()
# Юпи пришла.
# Привет, Юпи!

Смотрите, что получилось на последнем шаге. На этапе создания deco никакой код не выполняется -- мы заходим в deco, видим, что здесь определена функция wrapper и возвращаем ее. Таким образом мы подменяем исходную hey_Jupi на wrapper и получаем новое поведение hey_Jupi, не изменяя ее код!

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

@deco
def hey_Jupi():
print("Привет, Юпи!")

hey_Jupi()
# Юпи пришла.
# Привет, Юпи!

Кстати, этот же декоратор можно применить и к любой другой функции:

@deco
def take_five():
print("Юпи, дай пять!")

take_five()
# Юпи пришла.
# Юпи, дай пять!

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

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

В следующих постах разберемся, как комбинировать декораторы и передавать в декоратор параметры. Всем пять!🐠

#декораторы #функциональный_стиль #функции #основы
🔥1
Комбинируем декораторы

Допустим, у нас есть функции, которые работают со строками. Возьмем, например, функцию, которая возвращает строчку из Zen of Python:

def readability():
return 'Readability counts'

print(readability())
Readability counts

А теперь мы хотим, чтобы можно было показать текст в двух вариантах: жирным и курсивом. Вот два декоратора, один из которых добавляет тег <<жирный>>, а второй <<курсив>> :

def bold(func):
def wrapper():
return '<b>' + func() + '</b>'
return wrapper

def italic(func):
def wrapper():
return '<i>' + func() + '</i>'
return wrapper

Как уже договаривались в прошлом посте, запись

@bold
def readable():
return 'Readability counts'

Эквивалентна записи

readable = bold(readable)

И после применения декоратора вызов функции дает текст

print(readable())
<b>Readability counts</b>

А что если мы хотим получить текст одновременно и жирный и с курсивом? Можно сделать композицию декораторов:

@italic
@bold
def readable():
return 'Readability counts'

print(readable())
<i><b>Readability counts</b></i>

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

@bold
@italic
def readable():
return 'Readability counts'

print(readable())
<b><i>Readability counts</i></b>

Так получается из-за разного порядка выполнения функций: в первом случае мы сначала добавляем тэг <<жирный>>, а сверху оборачиваем в <<курсив>>:

readable = italic(bold(readable))

А во втором -- наоборот:

readable = bold(italic(readable))

Читаемость имеет значение! И порядок тоже. 🐠

#декораторы #композиция #функциональный_стиль
👍1🔥1
Знакомая, которая недавно устроилась на работу джуниором, рассказала, что в ее команде новым сотрудникам ставят цель либо закоммитить кусочек кода за день, либо задать два вопроса.

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

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

#онбординг #soft_skillz #личное
👍1
Давайте познакомимся

Я Маша Чакчурина, back-end разработчица🐠 Закончила физико-технический факультет в Питерском Политехе, занималась физикой Солнца, работала в компании СтарЛайн, и в их беспилотном автомобиле тоже. А год назад я переехала в Москву и проработала этот год в Касперском.

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

Я не верю, что можно научиться чему-то серьезному за пару дней. Для меня всегда работало узнавать вещи по чуть-чуть. Лучше дать себе время разобраться, чем потом жалеть, что пропустила и не успела. Поэтому я выбрала формат канала, где я могу делиться информацией маленькими порциями, чтобы я была уверена, что она укладывается.

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

Надеюсь, что этот канал вам помогает узнать что-то новое или повторить уже известное.

Что можно сделать для меня:

🐬 Если у вас есть друзья, которые учат или хотят учить Python, поделитесь с ними ссылкой.
🐬 Напишите мне, если хочется читать о чем-нибудь определенном, и я об этом расскажу.
🐬 Если думаете, что я могу быть вам полезна, предложите мне сотрудничество.
🐬 О личном я пишу в инстаграме, добро пожаловать в мой профиль.

Ну и всем успехов! А еще интересных, своих, драйвовых задач 🐠

#личное
1
​​IT во время COVID-19

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

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

Ниже подборка хакатонов и проектов, в которые можно вписаться pro bono, чтобы помочь в борьбе с эпидемией и ее последствиями:

Хакатоны:

Pandemic Response Hackathon пытаются лучше понять эпидемию и бороться с распростраением вируса.

CodeVsCOVID19 с очень большим количеством идей, как можно помочь.

Hack quarantine с нескольктими треками: supporting quarantined, tech and health, remote working, improving awareness and behaviour.

Задача на моделирование распространения вируса из Африки с призовым фондом.

На Kaggle:

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

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

ВОЗ хотят вычислить, какие именно факторы влияют на распространение вируса и смертность.

Проекты:

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

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

Другие списки:

helpwithcovid.com, который делает CEO OpenAI, собирает инициативы, там можно нафильтровать себе проект по навыкам/профессии.

Coronavirus handbook: еще больше проектов и сообществ для тех, кто может прогать.

Еще один список от 8000hours с большим гуглдоком, который постоянно обновляют.

В Twitter:

Ищите инициативы по хэштегу #COVTECH.

Если встретите еще интересные ссылки, скиньте их мне, пожалуйста, в личку или в фидбэк, а я дополню список. Лайк, репост, санитайзер. 🐠
👍1
​​​​Представьте, приходите вы на новый проект, заглядываете в логи, а там вперемешку с успешными запросами на сервер вот такие сообщения:

Unexpected exception:


Что-то постоянно ломается, но молча.

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

try:
raise KeyError
except Exception as e:
print(f"Unexpected exception: {e}")


Если выполнить этот пример, то и получится

Unexpected exception:


Дело в том, что есть четыре способа вывести сообщение пойманного исключения:

🐟 print(e)
🐟 print(str(e))
🐟 print(e.message)
🐟 print(repr(e))

Первые два варианта не очень информативны. Например, если попытаться обратиться к несуществующему ключу словаря (ошибка топ 1 в Python), то эти варианты выведут только название ключа.

my_dict = {}
try:
b = my_dict["bad"]
except Exception as e:
print(f"Unexpected exception: {e}")

Unexpected exception: 'bad'


Это потому, что str(e) и e выводят сообщение исключения, но не его тип. Чаще всего этого достаточно, но исключения для того и нужны, чтобы сообщать о ситуациях, которых мы не ожидаем.

Иногда пишут print(e.message). Здесь проблемы целых две: во-первых, мы по-прежнему получаем только сообщение. А во-вторых, атрибут message определен не у всех исключений. Если не снабдить наш print условием, то мы получим только новую ошибку:

AttributeError: 'KeyError' object has no attribute 'message'


А вот магический метод repr, который и нужен для того, чтобы давать максимально точное описание, все сделает отлично. Сравним:

try:
raise KeyError
except Exception as e:
print(f"Unexpected exception: {repr(e)}")

Unexpected exception: KeyError()


А в примере со словарем получилось бы

Unexpected exception: KeyError('bad')


что более явно, чем все три варианта выше 🐠

#исключения
🔥2
​​​​Хочу похвастаться: на этой неделе произошли сразу две приятные вещи.

1. После моего поста про исключения мне прислали крутой комментарий. Привожу целиком.

repr(e) -- это, конечно хорошо, но ведь есть ещё лучше, а именно:

from traceback import print_exc
...
my_dict = {}
try:
b = my_dict["bad"]
except Exception as e:
print_exc()

что выведет:

Traceback (most recent call last):
File "<pyshell#1>", line 2, in <module>
KeyError: 'bad'

и при этом программа продолжит свою работу. А если ошибку надо выводить не в stdout, то можно сделать так:

from traceback import print_exc
from io import StringIO
...
try:
b = my_dict["bad"]
except Exception:
buffer = StringIO()
print_exc(file=buffer)
out_var = buffer.getvalue()

2. Еще мне писали, что повторяли перед собеседованием Python по моему каналу. То есть, пользовались им ровно так, как я задумывала!

Вот ради таких моментов я и веду канал.

Кстати, если есть что-нибудь, о чем вы хотите прочитать, про Python, профессию или вообще, пишите @chakchurina, ответы на самые частые вопросы я публикую.
🔥1
Как устроены словари в Python, часть 1.

Представьте себе огромную библиотеку, в которой вы хотите найти «Пикник на обочине». Как это сделать?

Наивный способ — перебирать. Взять первую книгу, понять, что это не Стругацкие, поставить обратно, взять следующую, ... и так далее. В лучшем случае «Пикник на обочине» окажется в первой ячейке и мы справимся за один ход. В худшем придется перебрать все n книг библиотеки, за за O(n) шагов. Но можно быстрее.

Для этого определим функцию, которая получает название книги и возвращает число. Такая функция-справочник:

«Пикник на обочине» -> 1
«Декамерон» -> 2
«Уловка 22» -> 3
...

Положим «Пикник на обочине» на первую полку, «Декамерон» на вторую, и так далее. Когда нам понадобится книга, мы отправим название в эту функцию и сразу получим номер ячейки. Теперь книгу можно найти всего за два шага:

1) вычислить номер книги по названию,
2) найти ее на полке с этим номером.

Получается сложность O(1) и это очень быстро! Положить книгу на свое место тоже можно за фиксированное число шагов, вне зависимости от размера библиотеки. Побочным эффектом такого подхода будет то, что в библиотеке не будет дубликатов книг, ведь все копии Декамерона будут попадать в ячейку с одним и тем же адресом.

Функция, которая ставит объекту в соответствие число, называется хеш-функцией. Любая хеш-функция должна удовлетворять требованию:

Если два объекта идентичны, то их хеши равны.

Идеальная хеш-функция должна удовлетворять еще одному требованию:

Если у двух объектов одинаковый хеш, то это одинаковые объекты.

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

«Облачный атлас» -> 10
«Москва-Петушки» -> 10

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

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

И если вдруг оказывается, что «Облачный атлас» и «Москва-Петушки» нужно положить в одну и ту же ячейку, то такую ситуацию называют коллизией.

Способов бороться с хеш-коллизиями концептуально два.

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

Это как если положить все книги с одинаковым номером на одну полку. Тогда при поиске книги придется найти нужную полку, взять первую книгу и прочитать название. Если не та — проверить следующую, и так далее. В худшем случае все n книг попадут на одну полку и сложность получится O(n).

🐙 Открытая адресация. В этом случае в ячейки помещаются не указатели на списки, а сами пары ключ-значение. Алгоритм такой: вычисляем хеш-функцию, проверяем нужную ячейку. Если искомого элемента нет, то ищем в следующей ячейке. Следующую ячейку выбирают разными методами: это может быть просто фиксированный интервал до следующей ячейки, повторное хеширование вспомогательной хеш-функцией или другие методы.

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

В Python множествах и словарях используется метод открытой адресации.

Какие из всего этого выводы?

🐙 Ключи словаря должны быть хешируемыми.
🐙 Словари неэффективны по памяти. Если экономите память, используйте кортежи.
🐙 Поиск по ключу в итоге не O(1), но все равно очень быстрый.
🐙 Модифицировать словарь, по которому итерируешься — плохая идея. Интерпретатор может решить, что пора ресайзить хеш-таблицу и тогда старые данные переедут в новую табличку. Не стоит.

И все то же самое применимо к множествам, потому что они реализованы похожим образом.

🐙 А ещё становится понятно, что множества работают сильно быстрее списоков.

Кстати, пост не содержит совсем никаких рекомендаций, что почитать на досуге. 🐠

#словари #множества #реализация #алгоритмы #хеширование
👍2🔥1
Дублирование объектов в множестве

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

Создадим класс Client и добавим его в множество (сразу определила метод repr, чтобы были красивые принты):

class Client:
def __init__(self, user_name):
self.user_name = user_name

def __repr__(self):
return self.user_name

fish1 = Client(user_name="catfish")

clients = set()
clients.add(fish1)

print(clients) # {catfish}

Круто, все работает из коробки! Попробуем теперь добавить второй клиент, чтобы увидеть, что дублирования нет:

fish2 = Client(user_name="catfish")
clients.add(fish2)

print(clients) # {catfish, catfish}

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

Интерпретатор при добавлении объекта в множество следует правилу:

если a == b, то обязательно hash(a) == hash(b)

То есть, сравнивает между собой как сами объекты, так и их хеши.

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

print(fish1 == fish2) # False

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

🦑 в версиях Python 2.6 и ниже да, было просто hash(x) = id()
🦑
с версии 2.6 и выше: hash(x)==id(x)/16

То есть, рассчитывать на то, что hash(x) = id(), нельзя. Но можно рассчитывать на то, что Python объектах по умолчанию есть hash, который зависит от id() и на то, что хеш объекта в течение его жизни не меняется.

Так как в нашем примере объекты разные и располагаются в разных ячейках памяти, то

print(hash(fish1), hash(fish2)) # 8786876890805 8786876904409

Так что делать, чтобы объекты, которые мы хотим считать одинаковыми, схлопывались во множестве? Перегрузить методы hash и eq, чтобы в явном виде дать интерпретатору инструкцию, как сравнивать объекты и как рассчитывать хеш.

Для этого исправим определение класса:

class Client:
def __init__(self, user_name):
self.user_name = user_name

def __repr__(self):
return self.user_name

def __hash__(self):
return hash(self.user_name)

def __eq__(self, other):
if self.user_name == other.user_name:
return True
else:
return False

Теперь при добавлении объектов в множество все работает как ожидали:

clients = set()

fish1 = Client(user_name="catfish")
clients.add(fish1)
fish2 = Client(user_name="catfish")
clients.add(fish2)

print(clients) # {catfish}

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

🦑 Перегрузить методы hash и eq, причем оба, иначе не заработает
🦑 Если объекты идентичны, то и их хеши должны быть равны
🦑 В хэш-функцию должно попадать то, что однозначно идентифицирует объект
🦑 Хеш объекта не должен меняться в течение его жизни (иначе будете ловить чудеса в run time) 🐠

#словари #множества #реализация #хеширование
🔥1
Магические методы и пустые списки

Методы с двойным подчеркиванием в начале и в конце, например, __eq__, __hash__, __init__, в Python называют магическими методами. Их назвали так, потому что они добавляют магию в поведение класса.

Например, метод __init__ неявно вызывается при инициализации объекта:

Foo:
def __init__(self, a, b):
self.a = a
self.b = b

foo = Foo(7, 9) # вызывается __init__

print(foo.a, foo.b) # 7, 9

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

Зачем нам это? Это нестареющая классика: чтобы проверить, словарь или список на непустоту, начинающие часто используют стиль как в C++:

if len(a) != 0:
pass

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

if not a:
pass

И это работает ровно потому, что в момент if a: вызывается метод __bool__ класса список.

Для пользовательских объектов, где __bool__ не перегружен, по умолчанию возвращается True.

if foo:
print(True)
else:
print(False)

# True

Но если добавить

Foo:
def __init__(self, a, b):
self.a = a
self.b = b

def __bool__(self):
return False

То поведение изменится:

if foo:
print(True)
else:
print(False)

# False

Кстати, в случае, если метода __bool__ в классе нет, то интерпретатор будет искать метод __len__ (длина). Поведение такое же: если __len__ возвращает 0, то логическое значение оценивается как False.

Что с этим делать? Помнить, что falsy (значения, которые оцениваются как False) в Python это:

🐙 пустые словари {},
🐙 списки [],
🐙 кортежи (),
🐙 множества set(),
🐙 строки "",
🐙 пустые range(0),
🐙 нули любого численного типа: 0, 0.0, 0j
🐙 константы None и собственно False

А truthy значения это:

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

И писать проверку на непустоту красиво:

not a:
pass

#magic #dunder #bool #len #truthy #falsy #начинающим
🔥1
Как правильно произносить название языка?

По-простому говорят «питон», так же название языка и переводится.

За это можно огребсти в сообществе, потому что по-православному, канонично говорить «пайтон». Ведь создатель языка Гвидо Ван Россум назвал язык в честь шоу «Летающий цирк Монти Пайтона», которое он очень любил.

Кстати, название для шоу рождалось в муках. Среди имен, из которых выбирали, были:

- Owl Stretching Time,
- The Toad Elevating Moment,
- A Horse, a Spoon and a Bucket,
- Vaseline Review,
- Bun, Wackett, Buzzard, Stubble and Boot.

(непереводимая игра слов, суть которой сводится к тому, что могло быть несколько иначе)

Название шоу не означает буквально ничего, а слово Python выбрали, потому что хотели добавить в название склизкости за счет змеи.

Семейство змей, в свою очередь, назвал питонидами французский зоолог Франсуа-Мари Доден в честь дракона, которого, согласно мифу, умертвил Аполлон у входа в Дельфийский оракул. Дракона звали Пифоном.

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

#название #начинающим
1
Дэвид Бизли, звезда Python сообщества и автор бомбических докладов про асинхронность в Python, выпустил бесплатный курс Practical Python Programming.

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

Бизли сам пишет на Python 25 лет и половину этого времени преподает его, доверять можно. Очень рекомендую!
🔥1
Целочисленное деление

Как вы знаете, в Python есть два способа делить целые числа:

Оператор / при делении целого числа на целое возвращает результат типа float.

>>> 3 / 2
1.5 # float

А оператор // при делении целого на целое возвращает целое с округлением вниз, по-английски этот оператор еще называют floor division.

>>> 3 // 2
1 # int

Копалась в истории языка и узнала, что изначально деление целых чисел в Python было только целочисленное, и для него Гвидо использовал символ /. Но быстро стало понятно, что в языке, где программист не объявляет типы явно, использование такого символа неудобно и будет приводить к обилию ошибок в программах.

Поэтому часть сообщества (включая Гвидо) настаивала на том, что оператором целочисленного деления нужно выбрать символ //, а оператор деления, который возвращает тип float, должен быть /. Другие разработчики говорили, что целочисленное деление нужно писать как /, аргументируя это тем, что «научиться обращаться с целочисленным делением — это как обряд инициации для начинающих программистов», да и в C целочисленное деление пишется именно так.

Вот что Гвидо пишет об этом в своем блоге (в моем вольном переводе):

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

Я: Вот ты берешь два целых числа. Хорошо?
Она: Хорошо!
Я: Теперь ты можешь их сложить, вычесть, умножить в программе, правильно?
Она: Хм, конечно!
Я: А теперь предположим, что ты их делишь...
Она: Но в этом нет смысла! Целые числа образуют кольцо, а не поле. Ты ведь сказал, что взял эти числа из Z, верно?
Я: Ага.

Вот и все. Это точка зрения непрограммиста (с которой мне удобно согласиться). Целочисленное деление — это чушь и его не нужно писать как "/", даже если в C делают именно так;-)

Действительно, с точки зрения непрограммиста, целочисленное деление довольно странная история, ведь над целыми числами, как и над матрицами, нет деления в принципе!

Источники: [1], [2].

Кстати, я сейчас готовлю курс по пайтон для начинающих (не то чтобы я считала, что на рынке мало курсов, но я просто люблю учить людей). Как считаете, стоит добавить этот фрагмент в курс, или лучше вырезать?
👍1
Работа с JSON

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

Поэтому сделала лонгрид по JSON'у сама и делюсь с вами! Статью в PDF можно посмотреть на моем Patreon'e, она бесплатная. Рассчитана на уровень джуниоров и стажеров. В канал выложить не могу, потому что слишком много текста, а в тексте картинки, схемы и даже один мем!

Из головных болей: не получилось сверстать так идеально, как хотелось. Начала с LaTeX, поняла, что верстается долго, перешла в markdown, но там некрасиво легли картинки. Наконец, сделала в Notion и все равно недовольна. Дайте знать, если умеете красиво верстать без боли и адских страданий или можете рассказать, на какой платформе вам удобнее читать лонгриды.

🐠

Один из отзывов: Прочитал твою статью про json! Восторг! Ты так хорошо и спокойно объясняешь! Ты смогла мои обрывочные знания систематизировать.

Спасибо вам за такие хорошие слова🤍 Стараюсь для вас.
🔥1
Открываю курс по Python.

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

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

О курсе:
🐟 Теория и задачи ждут вас на платформе Stepik.
🐟 Сейчас курс продается за 2700 рублей и можно пройти первые 5 модулей. Остальные 7 модулей я открою для прохождения в течение 7 недель.
🐟 Я внимательно слежу за комментариями и буду обновлять и дополнять материал там, где это будет нужно.
🐟 Когда я открою последний модуль, цена вырастет в полтора раза. Так что предлагаю заинтересованным опередить меня!

Научиться писать на Python под моим наблюдением можно здесь.
👍1
Блок else в циклах

Многие теряются при виде блока else в циклах. А между тем в Python он используется не только в условных конструкциях. Рассмотрим на примере цикла for:
 
for i in range(1, 3):
print(i)
else:
print("loop finished normally")
# 1
# 2
# loop finished normally

Блок else выполняется, если выполняется условие выхода из цикла. Это значит, что если цикл прерывается как-то иначе, например, ключевым словом break или исключением, то блок else выполнен не будет:
 
for i in range(1, 4):
if i == 2:
raise Exception("error occurred")
else:
print("loop finished normally")
# Exception: error occurred

Чаще всего этим пользуются, когда ищут что-нибудь в цикле с использованием ключевого слова break:
 
numbers = [1, 3, 11, 5]
for number in numbers:
if number % 2 == 0:
print ("even number found")
break
else:
print ("no even numbers in the list")
# no even numbers in the list

С циклами while можете попробовать самостоятельно. 🐠

#циклы #for #while #else
🔥1
Печать списков

Если вдруг на собеседовании вам понадобится вывести список (или множество) чисел на печать одной строкой, то вот изящный способ это сделать:
 
>>> numbers = [1, 2, 3, 4, 5]
>>> print(*numbers)
1 2 3 4 5


Пользуйтесь! 🐠

#списки #множества #iterables #print
🔥1
Прямой эфир о резюме

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

Поэтому предлагаю вам вот такой формат: мы с моей коллегой, senior разработчицей и основательницей школы IT girl school Алисой проведем в четверг в 20:00 прямой эфир, на котором разберем и перепишем три джуниорских резюме. Увидите на примерах, как лучше писать, чтобы вас заметили работодатели.

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

На эфир приглашаем стажеров, джуниор программистов и тех, кто интересуется темой. Старт в 20:00 в четверг 24 декабря, участие бесплатное. Добавьте событие в свои календари, чтобы не забыть.

Ссылка на эфир: https://us02web.zoom.us/j/86743972942?pwd=eHVIeUFvSklGaUZaK3N2WnlUSDFxZz09
Резюме для разбора можно прислать мне или Алисе.

Ставьте огонек, если собираетесь прийти, чтобы я понимала, сколько нас будет🔥
👍1