Cool and Fun Python
540 subscribers
30 photos
8 videos
1 file
33 links
Крутой и весёлый Python. Случаи из практики и не только.
Download Telegram
Давным давно, в прошлом тысячелетии...
Регулярные выражения. Эпизод 4. Теоретический

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

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

В Python работа с регулярными выражениями осуществляется с помощью модуля re:
import re

Модуль предоставляет функции и методы для работы с регулярными выражениями, такие как re.search(), re.match(), re.findall() и кучу других.
Но если максимально упростить, модуль делает две вещи:

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

Познавательная минутка 🤓
Сырые строки (так же известные как raw string) в Python записываются как обычная строка, в одинарных или двойных кавычках. Но перед открывающей кавычкой ставится буквы r, сокращение от raw. Например сырая строка ниже может использоваться как шаблон для регулярного выражения из примера 3:
r'\b\w+\b'

2). Выбирать из большого текста маленький текст по шаблону.

Всё остальное - крутые навороты, упрощающие жизнь в поисках текста 🧠
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🤯21
This media is not supported in your browser
VIEW IN TELEGRAM
Всех причастных к международному женскому дню поздравляю с прошедшими праздником 💐

А вот и поздравление с регулярками подоспело:
import re

def congratulate(name):
pattern = r'(?i)\b(женщин\w*|девушк\w*|леди|дам\w*)\b'
if re.search(pattern, name):
return f"С Международным женским днем, {name}!"
else:
return f"С Международным женским днем!"

Обратите внимание на шаблон:
- для поиска без учёта регистра используется (?i);
- чтобы слово было словом, а не частью большого слова, используем \b до и после;
- для учёта любого окончания применяем \w* - любая буква ноль и более раз;
- вертикальная черта | работает как or. Достаточно одного из четырёх совпадений.

Если запустить, получим ожидаемый результат с упоминанием женщин или просто с поздравлением:
>>> congratulate("Дорогие женщины"))
'С Международным женским днем, Дорогие женщины!'
>>> congratulate("Уважаемые господа"))
'С Международным женским днем!'

P.S. Данный шаблон не даёт 100% гарантии 😉
>>> congratulate("Жан-Клод Ван Дамм")
Please open Telegram to view this post
VIEW IN TELEGRAM
👍32🔥1😁1
This media is not supported in your browser
VIEW IN TELEGRAM
Регулярные выражения

Выражение ?P<name> (ага, именно так, с большой P и треугольными скобками) используется для именования групп в регулярных выражениях, что делает код более читаемым и понятным.

Ловите простой пример использования ?P<name>:
import re

text = "Имя: Алексей, Возраст: 32, Город: Москва"

pattern = re.compile(r"Имя: (?P<name>\w+), Возраст: (?P<age>\d+), Город: (?P<city>\w+)")

match = pattern.match(text)
if match:
print("Имя:", match.group('name'))
print("Возраст:", match.group('age'))
print("Город:", match.group('city'))

В этом примере мы используем регулярное выражение с именованными группами для извлечения имени, возраста и города из текста. Функция match.group('name') позволяет получить значение, соответствующее группе с именем 'name'.

Когда увидел подобное использование регулярок, мне вспомнились словари. Копнув глубже, удалось совершить пару открытий 💡


Открытие номер 1, .groupdict()

Метод groupdict() используется для получения словаря, содержащего именованные группы из последнего успешного совпадения регулярного выражения. Он полезен, когда есть много именованных групп в регулярном выражении и вы хотите получить все значения в виде словаря.

Ловите пример с groupdict():
import re

text = "Имя: Алексей, Возраст: 30, Город: Москва"

pattern = re.compile(r"Имя: (?P<name>\w+), Возраст: (?P<age>\d+), Город: (?P<city>\w+)")

match = pattern.match(text)
if match:
group_dict = match.groupdict()
print(group_dict)

Результатом будет словарь group_dict, где ключами будут имена групп из шаблона pattern, а значениями - соответствующие значения из текста text.

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

✍️ - беру на вооружение
🤯 - как это работает?
🎉 - выходные для отдыха, а не кода
Please open Telegram to view this post
VIEW IN TELEGRAM
8👍3🤯3🎉3
Регулярные выражения. Открытие номер 2

Начало тут

Когда впервые познакомился с шаблоном ?P<name> в регулярках, прочитал в сети старую переписку Гвидо с...

Ага! С кем-то. Лично я запомнил его как Ларри Уолла, автора языка Perl. Но сейчас, при написании поста не смог найти ту самую древнюю переписку.
Если поделитесь ссылкой в комментариях, респект и уважуха. А пока будем считать это байкой старого айтишника. Садитесь поудобнее 😉


Когда Гвидо добавлял в язык Python регулярные выражения, он конечно же взял их из языка Perl. Почему?

Познавательная минутка 🤓
Perl был создан в 1987 году лингвистом Ларри Уоллом. И изначальная идея - язык для работы с текстом. А куда же тексту без регулярных выражений. Всё логично 🤓

Так вот, Гвидо захотел улучшить регулярки в Python. Он написал Ларри письмо, поинтересовался можно ли занять сочетание символов ?P (вопрос, заглавная P)? И Ларри сказал, что никаких планов на связку ?P у него нет.
После официально разрешения Гвидо использовал связку для расширения регулярок, добавил ?P<name>. Теперь он мог обращаться к найденным группам по имени. А заодно и складывать полученные группы в словарь по ключам.

Эта идея так понравилась, Ларри, что уже из Python перекочевала в Perl, а потом и в регулярные выражения как таковые.

Кстати, заглавная P в регулярке означает Python. Гвидо застолбил букву для своего языка. Вдруг регулярное выражение не прижилось бы.
Как показывает история, ?P<name> очень прижилось. И оно шикарно облегчает жизнь превращая объемный текст в словарь нужных данных.

Спасибо, Гвидо 🖖
👍6🔥2👨‍💻1
Несколько раз натыкался на вопросы и статьи про запуска кода по расписанию.

Хочет человек запускать свою функцию в 9:30 и 20:45. А ещё он пишет на Python. И начинаются варианты с time.sleep, с asyncio.sleep. Варианты с отдельными потоками или процессами. Кто-то использует сторонние модули, например schedule. Молодцы, ребята, чего уж. Много кодят ради запусков по расписанию 👍

Познавательная минутка 🤓
Запуск программ по расписанию использовался на компьютерах полсотни лет назад. Уже в 1970-х годах была программа (демон) для запуска других программ по расписанию. Вы когда-то слышали про cron? Это он претерпев несколько изменений запускает код по расписанию более 50 лет

Как вы догадались, для запуска когда по расписанию не нужно изобретать сложные Python костыли и велосипеды. Вводим в терминале crontab -e и добавим пару строк в конец файла:
30 9 * * * python /path/to/project.py
45 20 * * * python /path/to/project.py


Ура! Python файл project будет автоматически запущен дважды в сутки, в 9:30 (строка 1) и в 20:45 (строка 2) 😉

Заметили пустую строку после примера в cron? Как и Python фалы, файл crontab должен заканчиваться пустой строкой. Но в отличии от доброго Python, cron не прощает ошибки. Если пустой строки нет, cron проигнорирует последнюю. Ту, где запуск в 20:45.

P.S. Может ситуацию с последней пустой строкой и пофиксили. Но я за пару десятилетий привык её добавлять. Кому интересно, проверяйте, пишите результат в комментариях ✍️

#bash #crontab
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥31
И снова делюсь наболевшим. Улыбок вам и быстрых правок багов 💪😉

P.S. Пруфы из официальной документации

#юмор
😁51👍1
Гвидо ван Россум, создатель языка программирования Python, объявил о разработке собственной операционной системы. Отличительной особенностью новой ОС станет уникальная функция под названием GAL — Global Application Lock, позволяющая запускать за раз только одну программу.

«Мы стремимся к простоте и максимальной эффективности», — заявил ван Россум. «Без необходимости переключаться между задачами пользователи смогут полностью сосредоточиться на одной задаче, избежав отвлекающих факторов».

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

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

#юмор #неновости @notnewsgpt
😁4👍2🔥1
This media is not supported in the widget
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
1
Про многозадачность

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

- Почему не потоки? - спросите вы.

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

Познавательная минутка 🤓
Для запуска трёх задач в виде процессов использовал модуль subprocess
import subprocess
from sys import executable
from os import getcwd

...
python_executable = executable subprocess.Popen([python_executable, 'project_dir/main.py'], cwd=getcwd())
...


✍️ - беру на вооружение
🤯 - как это работает?

#многопоточность
Please open Telegram to view this post
VIEW IN TELEGRAM
🤯87👍1
Коротко об интересном

Недавно столкнулся с задачей выдернуть время из строки текста на русском языке.
Между созданием своего решения с нуля и поиском готового остановился на втором.
Представляю вашему вниманию rutimeparser.

Если коротко, то:
from rutimeparser import parse

text = "Завтра в 10:10"
date_time = parse(text, tz='Europe/Moscow')

✍️ - беру на вооружение
🤯 - как это работает?

#познавательно
4🤯4
Немного воспоминаний от автора канала

В далёком 2007 году я начал интересоваться Linux, особенно Gentoo. За пару дней скомпилировал ядро, модули, X11 и KDE. Всё с флагом -O3. Это означает, что операционная система адаптировалась под мой компьютер и стала быстрее и красивее, чем Windows XP. 🧓

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

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

Через несколько лет перешёл на CLD (Calculate Linux Desktop), который основан на Gentoo с KDE. Всё необходимое было собрано и скомпилировано за меня. Не только операционная система, но и сотни программ для работы с текстом, изображениями, видео и многим другим устанавливаются с нуля за 20 минут.

С опытом я перешёл к стабильности. Нет смысла устанавливать бета-версии программ, если есть стабильные, но на 1-2 версии ниже. И если сервис был создан 5 лет назад и успешно выполняет свои задачи, не стоит обновлять его.

Работает - не лезь. 🤓

👨‍💻 - юный и любознательный
🎅 - работает - не лезу
#истории
Please open Telegram to view this post
VIEW IN TELEGRAM
🎅7👍6👨‍💻3
Новое — это хорошо забытое старое.

ast.literal_eval

👍 - спасибо, что напомнил
✍️ - записал, иду изучать
🤯 - жду подробности в следующем посту

#познавательно
🤯13👍31
Целую неделю ждал хотя бы 10 реакций 🤯. Не дождался. Этот пост посвящается девятку интересующихся. 🫡

Что же такое ast.literal_eval ? Если просто и коротко, то это функция для превращения строки str в другой питоновский тип данных.
Смотрите пример, чтобы всё понять:
import ast

# Возвращает None
result = ast.literal_eval('None')
print(result) # None
print(type(result)) # <class 'NoneType'>

# Возвращает список
result = ast.literal_eval('[1, 2, 3]')
print(result) # [1, 2, 3]
print(type(result)) # <class 'list'>

# Возвращает словарь
result = ast.literal_eval('{"key": "value"}')
print(result) # {'key': 'value'}
print(type(result)) # <class 'dict'>


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

Внимание!
literal_eval удобно использовать, даже если вы не уверены в данных. Выполнить rm -rf / функция не сможет. Но будьте готовы отлавливать ошибки, если данные не поддаются преобразованию:
result = ast.literal_eval('a = 42')  # SyntaxError: invalid syntax
result = ast.literal_eval('Hi') # ValueError: malformed node or string on line 1: <ast.Name object at 0x7969dde980>


Для самых любопытных, напомню. 🤓
В Python есть модуль pickle. Он умеет мариновать питоновские типы в виде байт-файла. О нём писал тут и тут.

А ещё в Python есть модуль json. Он тоже умеет превращать строк в данные и наоборот. Про него я тут не писал. 🙃
#познавательно #lifehack
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍163🔥21🤔1
Столько реакций! Класс! Благодарю всех. 🥰

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

Все мы учителя и ученики одновременно. Всех нас с праздником, с днём учителя! 👨‍🏫
Please open Telegram to view this post
VIEW IN TELEGRAM
🎉13👍5👏2🤓1🤗1
Держите капельку знаний для работы с временем в Python. Речь пойдёт о timedelta - разнице между двумя точками во времени.
Решим простую задачу, сколько секунд прошло между двумя датами. Для простоты возьмём сегодняшнее число и время с интервалом в один час.

Вначале у нас всё хорошо.
from datetime import datetime

dt_gt = datetime(2024, 10, 10, 11, 11)
dt_lt = datetime(2024, 10, 10, 10, 11)
td = dt_gt - dt_lt
print(f'<{dt_gt}> - <{dt_lt}> = <{td}>')
print(f'{td.seconds = }')

# Результат
# <2024-10-10 11:11:00> - <2024-10-10 10:11:00> = <1:00:00>
# td.seconds = 3600


Из большего значения (более поздней даты) вычитаем меньшее значение. И получаем ожидаемую разницу в один час - 1:00:00.
У timedelta есть удобное свойство, seconds. Оно вернуло 3600 секунд.

Познавательная минутка 🤓
В одном часе 60 минут.
В одной минуте 60 секунд.
Следовательно в одном часе 60 × 60 = 3600 секунд.
А ещё в сутках 24 часа или 86400 секунд. Эти знания нам пригодятся после второго примера.

А теперь поменяем местами даты.
from datetime import datetime

dt_gt = datetime(2024, 10, 10, 11, 11)
dt_lt = datetime(2024, 10, 10, 10, 11)
td = dt_lt - dt_gt
print(f'<{dt_lt}> - <{dt_gt}> = <{td}>')
print(f'{td.seconds = }')

# Результат
# <2024-10-10 10:11:00> - <2024-10-10 11:11:00> = <-1 day, 23:00:00>
# td.seconds = 82800


Ранее мы убедились, что между датами 1 час или 3600 секунд. Но timedelta сообщает о разнице в 82800 секунд. 😨
Если присмотреться, timedelta теперь минус один день и плюс 23 часа.
Считаем -1 день = -24 часа.
-24 + 23 = -1 час или -3600 секунд.
Получается, что разница во времени посчитана верно. Но ожидаемы -3600 секунд мы не получили.

Что делать? 🤔 Смотреть пример 3.
from datetime import datetime

dt_gt = datetime(2024, 10, 10, 11, 11)
dt_lt = datetime(2024, 10, 10, 10, 11)
td = dt_lt - dt_gt
print(f'<{dt_lt}> - <{dt_gt}> = <{td}>')
print(f'{td.total_seconds() = }')

# Результат
# <2024-10-10 10:11:00> - <2024-10-10 11:11:00> = <-1 day, 23:00:00>
# td.total_seconds() = -3600.0


У объекта timedelta есть метод total_second. Он и вернул ожидаемые -3600 секунд. 🥳

Познавательная минутка 🤓
Доступ к свойству объекта осуществляется через точку. объект.свойство
Доступ к методу объекта осуществляется путём вызова метода, через имя и круглые скобки.
объект.метод()

Всем отличного времени, какая бы разница у него не была.

✍️ - беру на вооружение
🤯 - как это работает?

#познавательно #python
Please open Telegram to view this post
VIEW IN TELEGRAM
11👍4🤯1
print(10 / 2)       # 5.0
print(10 // 2) # 5
print(10.0 // 2) # 5.0
print(10 // 2.0) # 5.0
print(10.0 // 2.0) # 5.0

#юмор
2👍63😁3🤯1🎃1
Эволюция строки кода

В одном из проектов надо было разделить две переменных нацело. И в первой версии код выглядел как частное = делимое // делитель:
div = divisible // divisor


Проект развивался. И понадобился остаток от деления. Он использовался дальше по коду. Выбор пал на вариант 2, как более короткий:
# Вариант 1
div = divisible // divisor
mod = divisible % divisor

# Вариант 2
div, mod = divmod(divisible, divisor)


Любой проект не стоит на месте, эволюционирует. Понадобилось округлять остаток от деления в большую сторону. Но функция divmod так вписалась в проект, что решено было использоваться костыль маленькую хитрость с преобразованием типов:
div, mod = divmod(divisible, divisor)
div += int(bool(mod))

Да и остаток от деления всё так же нужен дальше по коду. 😉

Познавательная минутка 🤓
Если
вам нужно округлить вещественное число до целого в большую сторону, Python рекомендует использовать функцию ceil из модуля math стандартной библиотеки:
import math

div = math.ceil(divisible // divisor)


✍️ - беру на вооружение
🤯 - как это работает?

#познавательно #lifehack #python3k #python
Please open Telegram to view this post
VIEW IN TELEGRAM
59🤯6👍5
Маленькая привычка, которая решает большие проблемы

Вы когда-нибудь слышали про флаги?
🏴‍☠- это пиратский флаг;
🏁 а это финишный флаг;
True и False - пара, создающая логический флаг в программе.

Познавательная минутка 🤓
В программировании флаг - это переменная, которая может принимать только два значения: True или False.
Главная задача флага - показать, что что-то изменилось и что нужно на это отреагировать.

Так что за маленькая привычка из заголовка? Давать переменным-флагам имена, которые начинаются с is_:
- пользователь выиграл - is_win
- письмо отправлено - is_send_email
- идёт обработка большого массива данных и процесс не должен брать новые задачи. Он занят, он is_working_now

К таким именам быстро привыкаешь. Скорость написания и отладки кода повышается. А значит появляется время насладиться чашечкой кофе.

✍️ - беру на вооружение
🤯 - как это работает?
👍 - is_thanks

#познавательно #lifehack #python3k #python
Please open Telegram to view this post
VIEW IN TELEGRAM
👍189🤯2
Минутка ностальгии ☕️

Когда-то давным-давно я открыл для себя Python. Первая установка самой свежей на тот момент версии python3.4 была волнительной. Сколько открытий ждало впереди. 👨‍💻

Сегодня случайно обратил внимание, что поддержка 3.4 закончилась в 2019. Представляете, пять лет назад! 😔

Как быстро летит время. Даже боюсь вспоминать Java, который устанавливал на свой первый ПК лет этак 25 назад. 🥺

А какие у вас были языки программирования или версии, которые сейчас устарели? 😉

P.S. Ни слова про BASIC и Fortran. Они навеки в моём сердце. ❤️‍🔥
Please open Telegram to view this post
VIEW IN TELEGRAM
💔5👍43
Принимаем решение в словаре

Что обычно делают, если надо проверить условие? Конечно же используют конструкцию if.
Типичный пример:
a = 42
b = 73
if a > b:
print("Первое больше")
else:
print("Первое не больше")


Настолько просто, что в комментариях не нуждается.

А теперь избавимся от конструкции if else. Для этого перенесём логику принятия решения в словарь:
a = 42
b = 73
choice = {
True: "Первое больше",
False: "Первое не больше",
}
print(choice[a > b])


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


✍️ - беру на вооружение
🤯 - как это работает?
🎄 - с Новым годом и Рождеством

#познавательно #lifehack #python3k #python
216🎄8🤯7🔥2🤬1🏆1