Технологические заметки
10 subscribers
30 photos
1 video
20 links
Пишу блог для себя.
Основной контент: парсинги, автоматизация и аналитика.
Стек технологий: Python, VBA и пр.
Download Telegram
#ТаковПуть

Секрет отладочного вывода f-строк

Привычная запись f-строк
result = "hello"

print(f"result='{result}'")
# output: result='hello'

Начиная с python 3.8 можно сократить запись до:
result = "hello"

print(f"{result=}")
# output: result='hello'

Самое интересное, что на этом функционал не заканчивается! У нас никуда не пропали возможности взаимодействия с объектами

name = "Alice"
age = 30
score = 95.5
items = [1, 2, 3]

print(f"{name=} {age=} {score=:.1f}")
# name='Alice' age=30 score=95.5

print(f"{name.upper()=}")
# name.upper()='ALICE'

print(f"{age * 2=}")
# age * 2=60

print(f"{items=}")
# items=[1, 2, 3]

print(f"{len(items)=}")
# len(items)=3

Но надо помнить:
Эти фишки замедляют программу, поэтому для нас это только отладочный механизм.
#ТаковПуть

Отладка без IDE

Я придерживаюсь принципа, что программист должен уметь работать без IDE.

Без IDE достаточно сложно отлаживаться, особенно в проектах с серверами, например, django.

Однако в Python есть встроенная функция для отладки, которая не требует установки IDE!

def func(x, y):
result = x + y
breakpoint() # 👈 остановка
return result * 2

func(5, 3)

Когда код дойдет до breakpoint(), выполнение остановится и откроется интерактивная консоль отладки.

В консоли отладки можно:

· n (next) - выполнить следующую строку
· c (continue) - продолжить выполнение
· s (step) - войти в функцию
· p переменная - напечатать значение переменной
· l (list) - показать код вокруг текущей строки
· q (quit) - выйти из отладчика

С примером выше мы можем сделать так:
> python func.py
> p result
8
> c

После чего отладчик завершит работу, т.к. брейкпоинтов больше нет.
👍1
#ЧистыйКот #ТаковПуть

Логирование, которое НЕ захламляет код

На курсах, в книгах, в туториалах часто говорят, что надо уходить от print в пользу logging. И дальше показывают сложные настройки логирования прямо в самом коде.

Наверно, для обучения это неплохой вариант, но в реальных программах настройки логов и бизнес логика смотрятся, неуместно, когда лежат в одном модуле.
Я говорю об этом:
import logging
# настройки логирования
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('app.log'),
logging.StreamHandler()
]
)

# бизнес логика
def business_logic():
# какие-то очень важные вычисления...

Настройки логирования можно (и нужно!) выносить из кода в отдельные файлы! Самый простой вариант это ini файл.
[loggers]
keys=root

[handlers]
keys=fileHandler,consoleHandler

[formatters]
keys=defaultFormatter

[logger_root]
level=INFO
handlers=fileHandler,consoleHandler

[handler_fileHandler]
class=FileHandler
level=INFO
formatter=defaultFormatter
args=('app.log',)

[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=defaultFormatter
args=()

[formatter_defaultFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s

Файл *. ini является самым простым видом конфига, но модуль logging также поддерживает конфигурацию в формате dictionary (через logging.config.dictConfig), что часто удобнее и современнее

Считаю, что хорошим решением является вывести загрузку настроек в отдельный модуль:
# logging_config.py
import logging.config

class LoggingManager:
_configured = False

@classmethod
def get_logger(cls, name):
if not cls._configured:
cls._setup_logging()
return logging.getLogger(name)

@classmethod
def _setup_logging(cls):
logging.config.fileConfig('config.ini')
cls._configured = True

get_logger = LoggingManager.get_logger

Отдельный модуль для настроек удобен тем, что конфиг не всегда может покрыть все потребности. Например, в процессе работы программы могут появляться новые хендлеры. И в модуль можно добавить функционал добавления хендлеров и каких-то других важных вещей.

Теперь в основном коде подключение логирования будет выглядеть так:
# подключение логгера
from logging_config import get_logger
logger = get_logger(__name__)

# бизнес логика
def business_logic():
    # какие-то очень важные вычисления...

Как видно, основной код избавился от лишних строк, которые не относились к бизнес логике.

Выносите настройки логирования в конфиги — это делает код чище и профессиональнее!
#ЗаЧаем

Python взял курс на Rust.😱

Цитата из статьи:
Мы предлагаем внедрить язык программирования Rust в CPython. Сначала Rust будет использоваться только для написания дополнительных модулей расширения, но со временем он станет обязательной зависимостью CPython и будет разрешён к использованию во всей кодовой базе CPython.


Сама статья:
https://discuss.python.org/t/pre-pep-rust-for-cpython/104906
#ТаковПуть

Мост между будущим и прошлым Python!

Или как оставаться на передовой типизации, даже работая со старыми версиями Python!

Обычная ситуация для многих, когда выходит Python 3.14, а на работе 3.6, 3.7..3.10 и т.п. (нужное подчеркнуть).

И вот кодишь на работе проект на Python 3.6, а так хочется использовать современную типизацию. О которой все вокруг "трещат". И вот тут на помощь приходит...

typing_extensions

Для примера:
Self появился в Python 3.11, но благодаря typing_extensions код ниже заработает на Python 3.6

from typing_extensions import Self

class Database:
    def with_db(self) -> Self: 
        return self


А если проект написан на более новой версии Python, но необходимо его запустить на более ранней версии, то больше не надо половину кода с типизацией удалять из проекта. Эта библиотека дарит обратную совместимость типов!

Работает это так:
try:
from typing import Self
except ImportError:
from typing_extensions import Self

Т.е. просто заменяем импорт со стандартного typing на typing_extensions и (в теории) типизация из более новых версий python продолжит работать.


typing_extensions — это must-have для проектов, которые должны поддерживать старые версии Python и использовать современную типизацию!

Важно:
typing_extensions не заменяет полностью библиотеку typing, но большинство типов из новых версий Python будут работать.
#ВДзене

Долго не писал статьи в Дзене. Но, наконец, добрался до клавиатуры 😁

# 13 Индивидуальный план развития Python-разработчика

Наткнулся на статью развития фронтэнд разработчика и решил написать свой вариант, но для python-разраба.

#python #team

# 14 Telegram Bot прогноза погоды

Это копия моего предыдущего бота прогноза погоды, но на другой библиотеке. Как и прошлый бот, этот был сделан в похожем ООПэшном стиле.

#python #aiogram #TelegramBot #YandexAPI

🎯 В планах: написать опыт внедрения геймофикации, матриц компетенций и др

Предыдущие статьи.
#ТаковПуть

Библиотека pathlib в своей красе

Как и библиотека os, pathlib входит в стандартный набор библиотек для Python

Ниже прилагаю код, в котором пробегаюсь по некоторым возможностям библиотеки.
Сразу оговорюсь. Некоторые строки будут работать только в python 3.14.
from pathlib import Path

# Фиксируем расположение файла программы
program_path = Path(__file__)

# Рядом с программой будет располагаться папка data с вложенными файлами и папками
data_folder = program_path.parent / "data"
data_file = data_folder / "data.txt"
log_file = data_folder / "log.log"
archive_folder = data_folder / "archive"
archive_file = archive_folder / "archive.txt"

# Создание папки archive и всех ее родительских папок
archive_folder.mkdir(parents=True, exist_ok=True)

# Создаем файл data.txt
data_file.touch(exist_ok=True)

# Заполняем файл текстом
data_file.write_text("hello", encoding='utf-8')

# Копируем файл data.txt в папку archive
data_file.copy_into(archive_folder)

# Переименовываем файл data.txt в log.log
if not log_file.exists():
data_file.rename(log_file)

# Копируем содержимое файла log.log в data.txt
log_file.copy(data_file)

# Считываем текст файла data.txt, дополняем его и записываем в log.log
content = data_file.read_text(encoding='utf-8')
log_file.write_text(f'log: {content}')

# Удаляем все файлы .txt в папке data и ее подпапках
[file.unlink() for file in data_folder.rglob("*.txt")]


# Удаляем содержимое папки data
for item in data_folder.iterdir():
if item.is_file():
item.unlink()
elif item.is_dir() and not any(item.iterdir()):
# только пустые папки удаляются
item.rmdir()

# Удаляем пустую папку data
data_folder.rmdir()


Просто удивительно, насколько простая, лаконичная и мощная библиотека!
Когда будете очередной раз набирать import os, вспомните, что еще есть pathlib!
#ВДзене

Всем привет!

Прошлый раз Индивидуальный план развития Python-разработчика к статье в Дзен был готов только для частично. На этот раз я полностью расписал план развития от Падавана до Мастера. Удобнее всего открывать файл не в браузере, а через Obsidian.

Еще появилась новая статья:

# 15 Отправка писем через сервер Яндекса

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

#python #smtp

🎯 Из ближайшего: "Пошагово подготавливаем свою библиотеку для публикации в pypi". Уже готово, осталось только придумать как описать это текстом.

Предыдущие статьи.
#НГ #TelegramBot

Для коллег сделал бота с поздравительной открыткой.
https://t.me/PyTechNotesTreeBot

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

У меня в подписчиках только друзья и коллеги, поэтому кому интересно, пишите в личку, помогу сделать вам такую открытку.
2
This media is not supported in your browser
VIEW IN TELEGRAM
Всем привет!

Начал еще одно приложение писать. Ну как начал... Несколько месяцев туда-сюда, мысли, прототипы...

Думал делать в телеге, потом передумал, решил в вебе, потом передумал и решил на андройде.

В итоге вот начал пилить... Пока не с основного функционала, а настроек и хранения данных.

Тимометр — приложение для мониторинга компетенций сотрудников отдела :)
🔥1
#ТаковПуть

Дандеры

Все названия, которые имеют двойное нижнее подчёркивание, называются дандерами.

В python есть ряд важных нюансов, которые надо знать при работе с дандерами.

Тут я хочу коснуться только одного момента: когда переменная в классе имеет двойное подчеркивание "в начале" и "в начале и в конце"

class A:
def __init__(self):
self.__foo__ = 1
self.__foo = 2
a = A()
print(a.__foo__) # output: 1
print(a.__foo) # output: ошибка
print(a._A__foo) # output: 2

Интересная особенность классов в Python в том, что все дандер имена, которые начинаются с двойного подчёркивания (но не заканчиваются им), автоматически подвергаются name mangling (искажению имён). А если имя начинается и заканчивается двойным подчеркиванием, то название сохраняется.

Заблуждение многих питонистов, которые знают о механизме name mangling, заключается в том, что они считают, что это делается для сокрытия данных, но к переменной всё ещё можно получить доступ (это видно из последней строчки примера). Поэтому у механизма другая цель: избежать конфликтов имён в цепочке наследования.

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

Ну и вместо завершающего слова, пример, который на первый взгляд противоречит примеру и тексту выше.

class A:
    pass
a = A()
a.__foo = 3
print(a.__foo) # output: 3
print(a._A__foo) # output: ошибка

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

Всем привет!

Как и обещал, написал пошаговый план-гайд по созданию первой публичной Python-библиотеки.

Это цикл из шести статей о том, как сделать действительно «взрослую» библиотеку.

#16-21 Статья на все статьи

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

Плюс изюминка статей — это CI/CD от пуша кода до релиза в PyPI.

#python #cicd #pypi

Предыдущие статьи.
Увидел вот такую схемку про прожекта. Решил сохранить тут, т.к. информация хорошо структурирована.
Forwarded from Kaspersky
В свежем #kaspersky_securityweek:

🟢Злоумышленники атакуют программистов, задумавшихся о смене работы, с помощью вредоносных тестовых заданий. Они публикуют на LinkedIn и Reddit реалистичные вакансии, нацеленные на разработчиков ПО для индустрии криптовалют. Само тестовое задание на Python и Javascript, которое надо «запустить, улучшить и отладить», не содержит зловредов, но подключает их в виде зависимости.

🟢Эксперты «Лаборатории Касперского» подготовили большой отчёт о спаме и фишинге за 2025 год. Вкратце: 45% всех электронных сообщений оказались спамом. Что касается фишинга, пользователям часто предлагали бесплатные билеты на концерт, подарочные карты — или, например, плату за прослушивание песен в Spotify. Самыми популярными целями фишинга стали получение доступа к государственным цифровым сервисам и угон учётных записей в мессенджерах. В некоторых случаях у пользователя крали не только пароль, но и деньги. Также специалисты «Лаборатории Касперского» выпустили ещё два исследования: анализ стилера, замаскированного под компьютерную игру, и разбор нового инструментария группировки Head Mare.

🟢Пользователям аппаратных криптокошельков Trezor и Ledger рассылают настоящие бумажные письма с требованием «проверить авторизацию». QR-коды в письмах ведут на мошеннические сайты.

🟢Расширение AgreeTo для Microsoft Outlook, доступное с 2022 года, но заброшенное разработчиком, было угнано и использовалось в мошеннических целях. В результате были похищены данные четырёх тысяч учётных записей Microsoft.
Please open Telegram to view this post
VIEW IN TELEGRAM
#ВДзене

Всем привет!

Вышла новая статья в Дзен

#22 Telegram бот для публикации игры на Scratch

Помогал племяннице со школьным ИТ проектом и решил на эту тему написать статью.

Получился гайд для родителей, как игру на Scratch опубликовать в Telegram.

А вот и сама игра: @AlinaQuizLittlePrinceBot

#TelegramBot

Предыдущие статьи.
#ВДзене

Всем 🖖

Вышла новая статья в Дзен

#23 Как прокачать джунов

Давно хотел написать эту статью и наконец созрел. Делюсь опытом внедрения геймификации в команде low-code разработки.

#team

Предыдущие статьи.