Cool and Fun Python
540 subscribers
30 photos
8 videos
1 file
33 links
Крутой и весёлый Python. Случаи из практики и не только.
Download Telegram
А было что-то подобное ☝️ у вас?
Привет.
Поздравляю всех с Днём Победы. Счастья, радости, здоровья, мира и благополучия вам.

И ловите немного приветов миру 🕊
Традиционно изучение языка программирования начинают с вывода Hello world! И есть один классический способ для Python.
print('Hello world!')

Лично я знаю ещё парочку.
input('Hello world!')

И секретный способ.
import __hello__ 

У кого есть другие варианты, делитесь в комментариях. 😉

#познавательно
👍6🔥3
Что быстрее?
data_one = []
data_two = list()

Вопрос не про время набора, конечно же, а про время выполнения кода.
Ответ очевиден, если заглянуть под капот операции через модуль dis.
С квадратными скобками получаем:
  1           0 BUILD_LIST               0
2 STORE_NAME 0 (data_one)
4 LOAD_CONST 0 (None)
6 RETURN_VALUE

Функция list отработает чуть медленнее. Смотрите сами:
  1           0 LOAD_NAME                0 (list)
2 CALL_FUNCTION 0
4 STORE_NAME 1 (data_two)
6 LOAD_CONST 0 (None)
8 RETURN_VALUE

А если вам интересно продолжение этой истории, ставьте 👍 Тогда с меня подробные исследования в следующем выпуске.

#структуры_данных #познавательно
👍57🔥1
Продолжение истории про list() и [] оказалось длинным и с картинками. Пока решаю где её удобнее разместить. Продолжение однозначно следует...

А тем, кто недавно заглянул на огонёк сброшу ссылку на свой плейлист на YouTube. Если (а точнее когда) буду проводить вебинары, видео обязательно буду дублировать туда 👇

https://youtube.com/playlist?list=PL2Bb1BU5KbvphJCe7ZyOA611wXyRUQiux

#intro #видео
🔥5
Одна из историй преподавания или часть 1. Пара слов о рекурсии в Python

- Рекурсивный код предполагает вызов функцией самой себя.
Следовательно нам нужна функция
def func():

- Рекурсия обязана иметь базовый случай, когда она возвращает ответ. Без него получаем переполнение стека функций. А это страшнее зависания в бесконечном цикле 😈
Следовательно нам нужен
return result

- Вызов функцией самой себя должен упрощать задачу, приближать вычисления к базовому случаю.
Следовательно нам нужны передача аргументов
def func(*args, **kwargs):
и вызов себя с более простой задачей
return func(*spam, **eggs)

Собрав пункты вместе получим рекурсивный алгоритм. Например так можно считать сумму натуральных чисел от 1 до n через рекурсию:

def func(n):
if n == 1:
return n
return n + func(n - 1)


А если у вас не работает, ответ лежит 👉 тут 👈
👍6😁31🔥1
Одна из историй преподавания или часть 2. Пара слов про ленивые and и or в Python

Для повышения быстродействия при проверке условий в if, Python ленится, когда условий несколько в связке с and и/или or.

Вначале рассмотрим and.
True and True == True
True and False == False
False and True == False
False and False == False

А теперь читайте медленно слева направо. Замечаете? Если первым идёт False, то в итоге всегда будет False независимо от второго значения.

А теперь аналогичная "лень" для or.
True or True == True
True or False == True
False or True == True
False or False == False


В случае or если слева идёт True, то и в результате будет True.

Вывод. В 2-х случаях из 4-х проверки через and и or знают ответ заранее, не глядя на второе условие. Так зачем тратить вычисления.

if False and 2 + 2 == 4:
print("Этот текст никогда не будет выведен!")


Ленивый if помогает экономит ресурсы ☝️. Но новички легко наступают на грабли, не продумав все последствия 👇

if a > 0 or a / b > 1:
print("Текст")


В этом примере когда b = 0 получим ошибку деления на ноль. Но не всегда, а только если a <= 0.
👍8🔥2
Одна из историй преподавания или часть 3. Как благодаря ленивому and функция работает рекурсивно

def a(x):
return x and a(x - 1)


Перед нами квинтэссенция рекурсии и лени. При любом натуральном x функция рекурсивно досчитывает до нуля, который и возвращает.
1. Функция получает на вход натуральное число, например так print(a(5))
2. Происходит неявное преобразование целого числа 5 из int в логический True.
3. Функция переходит к проверке выражения после and и вызывает сама себя. Но число передаётся на единицу меньше.
4. Переходим к пункту 1.
4.1 В какой-то момент x уменьшается до нуля.
5 (он же новый п. 2). Происходит неявное преобразование целого числа 0 из int в логический False.
6. Ленивый if отказывается идти дальше and. Никакого нового вызова функции не происходит. Возвращается ноль.
7. Happy end и ответ в виде нуля при любом натуральном x на входе. Если конечно мы не переполняем стек вызова функций. Но это уже другая история... 😉
👍5👏52
Одна из историй преподавания или часть 4. Что за стек вызова функций из 1 и 3 части?

Каждый запуск функции кладёт на стек информацию о ней. Удаление информации происходит после завершения работы функции. И обычно стек почти пустой. Ведь даже в крутом выводе на печать списка уникальных элементов из введённой пользователем строки всего 6 функций максимально на стеке. 👇

print(list(set(map(str, input("Filter unique simbols: ")))))

С рекурсией ситуация хуже. Пример рекурсивного подсчёта суммы от 1 до n 👉 этот 👈 сломается на любом n больше ≈995. Стек не резиновый, ОЗУ не бесконечна. Стандартное ограничение в Python составляет 1000 элементов на стеке.

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

sys.setrecursionlimit(new_limit)

Но помните. С большим стеком приходит большая ответственность. 🕸
👍6🔥3
Чем заняться в выходные? Может почитать одно старое, но от этого ничуть не утратившее актуальность интервью со мной. 🤓
Хотя. Оно скорее не обо мне, а о Python. Но и вы собрались в канале ради языка программирования. Так что смело click по ссылке. 💻
https://habr.com/ru/company/habr_career/blog/454182/

Комментарии можно и туда, и сюда 🔁
🔥3👍1
This media is not supported in your browser
VIEW IN TELEGRAM
Изначально завершить историю о рекурсии хотел рассказом о хвостовой рекурсии и крутым приёмом по её реализации в Python. Да, язык изначально её не поддерживает. Но чем больше статей по оптимизации хвостов рекурсии в Python читал, тем больше слёз от костылей, кривокода и плясок с бубном текло из моих глаз 😢

В итоге пришёл к двум выводам.
1. Гвидо шикарный программист и я полностью согласен с его нежеланием заниматься Устранением хвостовой рекурсии.
2. Если есть рекурсивное решение задачи, но оно может переполнить стек, задачу надо переписать через циклы.

Было:
def func(n):
if n == 1:
return n
return n + func(n - 1)


Стало:
def func(n):
res = n
while n != 1:
n -= 1
res += n
return res


Или даже так, в Python Style:
def py_func(n):
return sum(range(1, n + 1))
🔥7
Если ваш код на Python активно взаимодействует с операционной системой... Или вы решили сделать простенький эмулятор терминала для прокачки навыков программирования. В любом случае обратите внимание на функцию system из модуля os.

os.system('python --version')
Быстро, просто, коротко.
👍5
Простенький эмулятор терминала ver_1.0.alpha из прошлого поста

import os

print('OS terminal started')
while True:
cmd = input('>>> ')
os.system(cmd)
UPD 12:30
Та неловкая ситуация, когда комментарии интереснее, чем сам пост. 😊
Программисты живут кодом. Но иногда надо отдыхать. И я не про сон и еду, без которых никак. Прогулка, пробежка, поездка на велосипеде, поход подальше от цивилизации с ночёвкой. Дела и места без ноутбука, интернета, а иногда и без электричества.
Но что делать, если гениальная мысль пришла именно в такой момент?

Мой личный Top-3 для Android телефона Python-разработчика. 😉

PyDroid 3 лучшая из мобильных IDE, которые встречал. Она может не только код 🤓
Консоль, терминал интерпретатора, pip, отладчик,... 😍 https://play.google.com/store/apps/details?id=ru.iiec.pydroid3

CodeBoard клавиатура отлично помогает уйти от багов автозамены. А когда к ней привыкаешь, уровень восторга зашкаливает 😊 https://play.google.com/store/apps/details?id=com.gazlaws.codeboard

Pocket Git великолепно справляется с базовыми операциями. А синхронизироваться с облаком можно по возвращению из похода. 💡
https://play.google.com/store/apps/details?id=com.aor.pocketgit

Если у вас есть свои любимые телефонные программы ITшника, делитесь в комментариях.
👍8
В Python логический тип данных (он же класс bool) основан на целых числах, т.е. на классе int.
Есть лишь две логических константы True и False.
И так как "логика" основана на "целых", константы могут участвовать в математических выражениях.
True преобразуется в единицу, а False в ноль.

>>> 4 + True
5
>>> 5 / False
ZeroDivisionError: division by zero
Один из вариантов применения - получить переменную знак (+1 или -1) из логической:
sign = is_bool * 2 - 1
Теперь можем оперировать числом или его инвертированным значением:
res = data * sign
👍6
Кстати, про истину и ложь. Все давно перестали замечать последнюю строку вывода ваших программ. Вот эту:

Process finished with exit code 0

Ноль в конце говорит об успешном завершении программы. Для ОС ноль как раз является истиной. А если программа завершается с ошибкой, получаем какое-то отличное от нуля число. И это плохо, это ложь.
Как быть? Понять и простить знать об этой особенности. И может быть вспомнить Zen Python: "Явное лучше неявного". 🤓
2👍2
Когда-то давно в одном проекте нужна была система помощи в принятии решения. Не буду вдаваться в подробности. 🤐
Но проверить работу кода решил не через тест-кейсы, а сразу на реальных данных. Взял из DB "CША" и...
Код не заработал. Спустя несколько часов в попытках найти баг составил в корне новый алгоритм и написал вторую версию кода. И снова ничего. Часы отладки, а результата нет. 😔

В чём была проблема узнал лишь на следующий день, когда сделал это:

data = "CША"
for char in data:
print(ord(char))


Буква "C" оказалась латинской, а "ША" из кириллицы. 😱

Так я впервые познакомился с набором из 11 заглавных и 6 строчных букв, а именно: "А, В, С, Е, Н, К, М, О, Р, Т, Х, а, с, е, о, р, х." Внешне они одинаковы, но код для латиницы и кириллицы разный. 🤓

В тот же день была написана обёртка к коду, которая исправляет случайный ввод пользователя и приводит символы к нужной раскладке. 😎

И да, с тех пор глядя на строки зелёного кода я могу разглядеть девушку в красном платье. 💃
6🔥4😁4👍3
Ура!!! 🎉 Модераторы Хабра пропустили мою статью о сравнении list() и [] https://habr.com/ru/post/671602/
Начало идеи в канале, вот тут: https://t.iss.one/CoolAndFunPython/26

Кстати, это первая статья именно от меня, а не через компанию, журналиста и т.п. 😍 Приятного чтения. И пусть такты процессора греют не только вашу комнату, но и душу. 😉
11🔥1
Кто-то скажет, что это повтор и спам. А я скажу, что внутренние алгоритмы Google тратят ≈4 дня от момента публикации статьи до её рекомендации.
С другими статьями, на которые "подписан" ситуация аналогичная. Всё дело как в огромном интернете, так и в почти 5 миллиардах его пользователей.

Если максимально упростить рекомендательный алгоритм, получим:
Поисковый робот обходит интернет раз в сутки. +1 день на поиск статьи.
Внутренняя DB формируется в удобный для рекомендаций вид. +1 день на базу.
Рекомендательная система сравнивает базу интересов пользователя с базой статей в поисках совпадений. +1 день на сравнение.
Статья появляется в списке рекомендуемых при включения браузера. В этот момент он получает готовый список от поисковика. 🤓

P.S. Как же системе удаётся рекомендовать "свежак"? Синхронизация всех этапов, конечно же. Статья, спустя несколько минут плановый обход ботом, спустя минуты работа с базами, следом успевает поиск по интересам, а тут и пользователь открыл браузер. Бинго. 👍
👍61
Расширим знания о "магических" файлах. 🧙‍♀️

Допустим у нас есть каталог project с файлами begin.py, work.py и другими. Большинство Python разработчиков знают, что добавление пустого файла __init__.py в директорию проекта превращает её в питоновский пакет.

Первый уровень магии
Создаём пустой файл __init__.py Теперь мы можем написать в коде:
import project
и далее вызывать project.begin или project.work.

Второй уровень магии
В файл __init__.py помещаем нужный нам код. При импорте директории:
import project
мы автоматически запустим содержимое файла «инит».
Например, файл содержит строку кода:
print("Hello from init")
После импорта в другом файле с расширением py или в интерпретаторе, мы увидим вывод в консоли:
Hello from init

Высший уровень магии
Добавляем в директорию project файл __main__.py Теперь Python может запускать project как исполняемый файл. Пишем в консоли операционной системы(!):
python project
и тут же выполняется содержимое «мейна». Высшая магия позволяет уйти от импорта и от интерпретатора Python. Теперь мы работаем с питоновским каталогом непосредственно из нашей ОС.
Например «мейн» содержит код:
print(f"Hello from {__name__}.py")
При запуске через ОС увидим в консоли:
Hello from main.py

Приём с «инит» и «мейн» позволяет автоматизировать запуск Python скриптов по расписанию, упростить процесс первичной инициализации и вообще облегчает работу разработчика. 😎
👍144
А вот вам пример тестирования «инит» и «мейн» на Андроид перед написанием поста.
Программист всегда программист. 😉
👍6
Сталкивались ли вы с ситуацией, когда огромный словарь (список, JSON) невозможно нормально прочитать? Глазами, а не из-за проблем с доступом. 👀

Берём на вооружение "заикающийся принт". 👇

from pprint import pprint


Двойное "P" не заикание, а сокращение. Pretty print. Красоту он даёт при выводе словарей (и не только их).

Пример 1. Словарь
data_dct = {"text": "one", "new_text": 22, "other_text": [1, 2, 3], "any_text": "any_text", "data_object": None}
pprint(data_dct)


Вывод:
{'any_text': 'any_text',
'data_object': None,
'new_text': 22,
'other_text': [1, 2, 3],
'text': 'one'}


Обратите внимание, что при выводе ключи словаря сортируются в алфавитном порядке.

Пример 2. Словарь со списком словарей
data = {"complet":[{"id":286050,"score":10,"username":"Юрий","title":"Деревья","chapter":18,"seen":True},{"id":255762,"score":5,"username":"Алексей","title":"Ветви","chapter":8,"seen":True},{"id":284531,"score":8,"username":"Алексей","title":"Листья","chapter":7,"seen":True},{"id":845560,"score":3,"username":"Юрий","title":"Корни","chapter":27,"seen":False}],"pending":[{"id":282400,"score":5,"username":"Владимир","title":"Трава","chapter":3,"seen":True},{"id":35388,"score":35,"username":"Вероника","title":"Кусты","chapter":6,"seen":False},{"id":80718,"score":7,"username":"Юрий","title":"Грибы","chapter":6,"seen":True}],"complet_count":4,"pending_count":3}
pprint(data)


Вывод:
{'complet': [{'chapter': 18,
'id': 286050,
'score': 10,
'seen': True,
'title': 'Деревья',
'username': 'Юрий'},
{'chapter': 8,
'id': 255762,
'score': 5,
'seen': True,
'title': 'Ветви',
'username': 'Алексей'},
{'chapter': 7,
'id': 284531,
'score': 8,
'seen': True,
'title': 'Листья',
'username': 'Алексей'},
{'chapter': 27,
'id': 845560,
'score': 3,
'seen': False,
'title': 'Корни',
'username': 'Юрий'}],
'complet_count': 4,
'pending': [{'chapter': 3,
'id': 282400,
'score': 5,
'seen': True,
'title': 'Трава',
'username': 'Владимир'},
{'chapter': 6,
'id': 35388,
'score': 35,
'seen': False,
'title': 'Кусты',
'username': 'Вероника'},
{'chapter': 6,
'id': 80718,
'score': 7,
'seen': True,
'title': 'Грибы',
'username': 'Юрий'}],
'pending_count': 3}
👍18🔥4