uk
Feedback
Python Заметки

Python Заметки

Відкрити в Telegram

Интересные заметки и обучающие материалы по Python Контакт: @paulwinex ⚠️ Рекламу на канале не делаю!⚠️ Хештеги для поиска: #tricks #libs #pep #basic #regex #qt #django #2to3 #source #offtop

Показати більше
2 373
Підписники
Немає даних24 години
-17 днів
-1130 день

Триває завантаження даних...

Хмара тегів
Немає даних
Виникли проблеми? Будь ласка, оновіть сторінку або зверніться до нашого support-менеджера.
Вхідні та вихідні згадування
---
---
---
---
---
---
Залучення підписників
липень '25
липень '25
+2
в 0 каналах
червень '25
+7
в 0 каналах
Get PRO
травень '25
+1
в 0 каналах
Get PRO
квітень '25
+1
в 0 каналах
Get PRO
березень '25
+7
в 0 каналах
Get PRO
лютий '25
+7
в 0 каналах
Get PRO
січень '25
+5
в 0 каналах
Get PRO
грудень '24
+25
в 1 каналах
Get PRO
листопад '24
+7
в 0 каналах
Get PRO
жовтень '24
+9
в 0 каналах
Get PRO
вересень '24
+6
в 0 каналах
Get PRO
серпень '24
+4
в 0 каналах
Get PRO
липень '24
+9
в 0 каналах
Get PRO
червень '24
+8
в 0 каналах
Get PRO
травень '24
+23
в 0 каналах
Get PRO
квітень '24
+20
в 0 каналах
Get PRO
березень '24
+18
в 0 каналах
Get PRO
лютий '24
+28
в 0 каналах
Get PRO
січень '24
+36
в 0 каналах
Get PRO
грудень '23
+32
в 0 каналах
Get PRO
листопад '23
+28
в 0 каналах
Get PRO
жовтень '23
+23
в 0 каналах
Get PRO
вересень '23
+32
в 0 каналах
Get PRO
серпень '23
+28
в 0 каналах
Get PRO
липень '23
+14
в 0 каналах
Get PRO
червень '23
+16
в 0 каналах
Get PRO
травень '23
+29
в 0 каналах
Get PRO
квітень '23
+11
в 0 каналах
Get PRO
березень '23
+19
в 0 каналах
Get PRO
лютий '23
+18
в 0 каналах
Get PRO
січень '23
+19
в 0 каналах
Get PRO
грудень '22
+27
в 0 каналах
Get PRO
листопад '22
+34
в 0 каналах
Get PRO
жовтень '22
+26
в 0 каналах
Get PRO
вересень '22
+18
в 0 каналах
Get PRO
серпень '22
+25
в 0 каналах
Get PRO
липень '22
+24
в 0 каналах
Get PRO
червень '22
+16
в 0 каналах
Get PRO
травень '22
+87
в 0 каналах
Get PRO
квітень '22
+45
в 0 каналах
Get PRO
березень '22
+265
в 0 каналах
Get PRO
лютий '22
+36
в 0 каналах
Get PRO
січень '22
+89
в 0 каналах
Get PRO
грудень '21
+22
в 0 каналах
Get PRO
листопад '21
+119
в 0 каналах
Get PRO
жовтень '21
+144
в 0 каналах
Get PRO
вересень '21
+15
в 0 каналах
Get PRO
серпень '21
+77
в 0 каналах
Get PRO
липень '21
+30
в 0 каналах
Get PRO
червень '21
+188
в 0 каналах
Get PRO
травень '21
+26
в 0 каналах
Get PRO
квітень '21
+27
в 0 каналах
Get PRO
березень '21
+44
в 0 каналах
Get PRO
лютий '21
+44
в 0 каналах
Get PRO
січень '21
+1 815
в 0 каналах
Get PRO
грудень '20
+1 235
в 0 каналах
Дата
Залучення підписників
Згадування
Канали
23 липня0
22 липня+1
21 липня0
20 липня0
19 липня0
18 липня0
17 липня0
16 липня0
15 липня0
14 липня0
13 липня0
12 липня0
11 липня0
10 липня0
09 липня0
08 липня0
07 липня+1
06 липня0
05 липня0
04 липня0
03 липня0
02 липня0
01 липня0
Дописи каналу
В Python 3.14 появится реализация PEP 750 и новый способ форматирования: t-strings. Это так называемые Template Strings. Синтаксис такой же как с f-strings, но форматирование происходит не сразу. Вместо строки создаётся объект Template, который внутри себя содержит исходную информацию, сырую строку (template.strings) и переменные (template.values). Это позволяет произвести дополнительную обработку данных перед форматированием, например для усиления безопасности. В примерах можно увидеть как строка с HTML кодом дополнтиельно обрабатывается чтобы избежать инъекции JS кода за счет экранирования служебных символов. Конечно, этим примером возможности не ограничивюатся. Более подробно про функционал будет понятно ближе к релизу в конце года. Сейчас доступно в сборках 3.14.0a7+ из этой ветки. Простой пример создания шаблона
name = "World"
template = t"Hello {name}!"
Что является шорткатом для
from string.templatelib import Template, Interpolation

template = Template(
  "Hello ",
  Interpolation(value="World", expression="name"),
  "!"
)
В обоих случаях объект получим идентичный
print(isinstance(template, Template))
# True
print(template.strings)
# ("Hello ", "!")
print(template.values)
#(name,)
Больше примеров ➡️ здесь #pep

2
С праздником, девушки! 💐☀️💖
С праздником, девушки! 💐☀️💖
0
3
Небольшая вспомогательная функция для запуска процессов. Что умеет: ▫️запускать сабпроцесс в обычном режиме с перехватом текущего терминала ▫️запускать процесс без терминала ▫️запускать детаченый процесс (никак не привязан к текущем процессу) ▫️запускать в отдельном терминале как дочерний с блокировкой, без блокировки и детаченый. ▫️передавать переменные окружения для нового процесса ▫️перенаправлять аутпут детаченого процесса в файл (полезно если он без терминала) Забираем здесь ↗️ #sources
0
4
Всех с Новым Годом!!! ❄️🎄💥🥂⛄️ Между прочим, год питона змеи)) 🐍
Всех с Новым Годом!!! ❄️🎄💥🥂⛄️ Между прочим, год питона змеи)) 🐍
0
5
Pyrogram закрылся! Популярная библиотека pyrogram больше не будет развиваться. 24-го декабря мейнтейнер перевёл репозиторий в
Pyrogram закрылся! Популярная библиотека pyrogram больше не будет развиваться. 24-го декабря мейнтейнер перевёл репозиторий в архив и написал сообщение с разъяснениями. Если вы используете pyrogram в своих проектах, то у меня для вас плохая новость. Когда в Telegram появятся новые функции или изменится API, ваш проект перестанет работать. Рекомендую оперативно его переписывать. Актуальная альтернатива - Telethon ➡️ https://github.com/LonamiWebs/Telethon Документация здесь 📖 https://docs.telethon.dev/en/stable/ #libs
0
6
JSON API сейчас весьма актуален в сфере веб-приложений. Но у стандартной библиотеки json есть проблема - она относительно медленная. Если ваше веб приложение должно тянуть держать нагрузку, то такие популярные операции как сериализация и десериализация JSON хорошо бы максимально оптимизировать. Каждый запрос это преобразование JSON-строки в объект, обработка запроса, и обратное кодирование объекта в JSON-строку. Буквально - каждый! Исходные данные для теста: file = 'data.json' # 156kb with open(file, 'r') as f: file_data = f.read() data = json.loads(file_data) count = 50000 Сделаем эталонный замер стандартной библиотеки start = time.perf_counter() for i in range(count): json.loads(file_data) end = time.perf_counter() json_time_decode = end - start start = time.perf_counter() for i in range(count): json.dumps(data) end = time.perf_counter() json_time_encode = end - start print(f'Json time: {round(json_time_decode, 2)}s/{round(json_time_encode)}s') # Json time: 50.04s/40s Итак, какие есть альтернативы? Сравнивать будем с библиотеками orjson и ujson. Код находится на github, а здесь приведу только результаты. Json time: 50.04s/40s Orjson time: 20.27s [2.47x speed] / 5.46s [7.35x speed] Ujson time: 47.29s [1.06x speed] / 35.04s [1.15x speed] Неплохой прирост с orjson я считаю! А вот ujson не особо опередил. Тест проводился на Windows 10. Интересно, что на Linux ujson даже медленней чем стандартный. Но, думаю, это у меня какие-то проблемки. В тесты я не добавил simplejson. Он не сильно быстрей стандартного модуля. Если вы пишете приложения на FastAPI, то в 3 строки можете ускорить обработку JSON-ответа! Есть встроенный класс для этого. 1. Установка poetry add orjson # or pip install orjson 2. Имопрт from fastapi.responses import ORJSONResponse # Там же лежит и UJSONResponse 3. Подключение app = FastAPI( ... default_response_class=ORJSONResponse ) Для Django тоже есть решение: drf-orjson-renderer #libs
0
7
Доделал свой старый проект - инструмент для восстановления ориентации объектов в пространстве на основе опорных компонентов. Работает в Autdesk Maya. Основные возможности. ▫️просто выделите опорные (обычно симметричные или осевые) компоненты и укажите куда их ориентировать ▫️ операции для доворотов и центрирования ▫️ восстановление исходного расположения после восстановления трансформаций ▫️работает как с одним объектом так и с группой ▫️ открытый API для интеграций с другими инструментами и автоматизаций Все действия происходят с векторами и матрицами объектов, поэтому всё достаточно быстро. Где может применяться? 🪑Нередкая проблема - собрали лейаут сцены и зафризили, или даже смержили всю геометрию в один большой меш. Требуется вернуть все объекты в "Т-позу", сохранить отдельно и расставить обратно в сцену, но с правильными трансформациями. Инструмент как раз заточен под такую работу. 🌲Заскатерили инстансы и потом конвертнули в меш. Нужно обратно преобразовать в инстансы. Здесь поможет API который восстановит положение каждого инстанса в нуле и вернёт его обратно в исходное положение, но с правильными трансформациями. Останется забрать матрицу с объекта для инстанса. Быстрое превью функционала: ▶️ https://www.youtube.com/watch?v=JvlHa0NEXu8 Документация и код здесь: 🌍 https://github.com/paulwinex/pw-maya-restore-orient #release #source
0
8
Всех причастных с 3Dекабря! ✨😵‍💫💥 @offtop
Всех причастных с 3Dекабря! ✨😵‍💫💥 @offtop
0
9
⭐️ Всем привет. Я завершил очередной проект! Он еще не достаточно причёсан чтобы добавлять в портфель, но как только, так сра
⭐️ Всем привет. Я завершил очередной проект! Он еще не достаточно причёсан чтобы добавлять в портфель, но как только, так сразу добавлю в галерею. А пока я открыт к предложениям по работе. Фултайм удалёнка. Вся инфа здесь https://paulwinex.com/resume Контакт: @paulwinex
0
10
Как добавить директорию в игнор git репозитория. 1. Те, кто работает JetBrains-продуктах уже на автомате добавляют в .gitignore строчку: .idea/. Это самый простой способ. 2. Чтобы не добавлять в каждом проекте можно добавить в глобальный игнор файл. По умолчанию он лежит здесь: ~/.config/git/ignore Либо указать другой путь через конфиг git config --global core.excludesfile ~/.gitignore Кстати, библиотека venv в Python 3.13 по умолчанию в корень вирутального окружения добавляет файл .gitignore с одним символом *, что означает исключение всего в текущей директории. Таким образом папка с venv автоматически исключается из репозитория. Удобно. #tricks
0
11
Что нового добавили в REPL в Python 3.13 На самом деле серьезно его прокачали! ▫️Както я писал, что для выхода из REPL приходится писать exit, еще и скобки для вызова. И было бы удобней сделать это по аналогии с обычным терминалом. Видимо, я не один такой😁 В новом REPL добавили несколько команд: exit или quit: для выхода. Именно так, без вызова функции! clear: для очистки терминала help или F1: для входа в режим справки (q для выхода) ▫️ Автокомплит по TAB аналогичный Linux-терминалу. Одиночный TAB заполняет самое пхожее совпадение, двойной показывает все доступные варианты. Эти варианты фильтруются по мере набора. ▫️ Ранее при вставке многострочного кода с пустыми строками мы получали ошибку IndentationError, теперь это исправили. Хотя, в некоторых терминалах это даже с 3.6 работает нормально, но зависит от конкретной реализации именно терминала а не Python. На винде точно не работает до 3.13. Пример кода для теста в 3.12 и 3.13 class A: def test(self): pass ▫️ История ввода теперь учитывает многосрочные команды.При нажатии стрелки вверх появятся все строки из прошлого многосрочного ввода, по ним даже можно перемещаться и редактировать. По нажатию F2 можно открыть всю историю ввода. ▫️ Колоризация кода для tracebacks и doctest. Также я заметил что имеет цвет промт функции input(). Кстати, для тестов на винде без установки можно использовать портейбл версию из проекта WinPython. #release
0
12
А вот и наглядное использование контроля стилей через свойства виджета. Билиотека qt-material. В этом разделе написано, что ч
А вот и наглядное использование контроля стилей через свойства виджета. Билиотека qt-material. В этом разделе написано, что через свойство class можно контролировать цвет кнопки, по аналогии с css стилями. btn_danger.setProperty('class', 'danger') btn_warning.setProperty('class', 'warning') btn_success.setProperty('class', 'success') #libs #qt
0
13
Установить свойства виджета в PySide можно не только через соответствующие методы и конструктор класса. Можно их изменять с помощью метода setProperty по имени. btn = QPushButton("Click Me") btn.setProperty("flat", True) Это аналогично вызову btn.setFlat(True) Если указать несуществующее свойство, то оно просто создается btn.setProperty("btnType", "super") Получить его значение можно методом .property(name) btn_type = btn.property("btnType") Когда это может быть полезно? ▫️Можно просто хранить какие то данные в виджете и потом их доставать обратно widget = QWidget() widget.setProperty('my_data', 123) print(widget.property('my_data')) ▫️ Назначая эти свойства разным виджетам можно потом отличить виджеты во время итераци по ним. Например, найти все кнопки со свойством my_data="superbtn". Но ведь вместо кастомного свойства можно использовать objectName, будет тот же результат. Да, но y ObjectName есть ограничение - только строки. ▫️ Если нам потребуется не просто поиск а, например, сортировка по числу, то свойства позволяют нам это сделать. Поддерживается любой тип данных widget.setProperty('my_data', {'Key': 'value'}) widget.setProperty('order', 1) all_widgets.sort(key=w: w.property('order')) Но ведь Python позволяет всё вышеперечисленное сделать простым созданием атрибута у объекта widget.order = 1 widget.my_data = 123 Да, но я думаю что не надо объяснять почему не стоит так делать. К тому же, если у виджета нет свойства то метод .property(name) вернет None, а отсутствующий атрибут выбросит исключение. ▫️ Действительно полезное применение кастомным свойствам - контроль стилей. Здесь атрибутами не обойтись, нужны именно свойства. Дело в том, что в селекторах стилей можно указывать конкретные свойства виджетов на которые следует назначать стиль. Просто запустите этот код from PySide2.QtWidgets import * if __name__ == "__main__": app = QApplication([]) widget = QWidget(minimumWidth=300) layout = QVBoxLayout(widget) btn1 = QPushButton("Action 1") btn2 = QPushButton("Action 2") btn3 = QPushButton("Action 3", flat=True) layout.addWidget(btn1) layout.addWidget(btn2) layout.addWidget(btn3) # добавим кастомное свойство одной кнопке btn1.setProperty("btnType", "super") # добавляем стили widget.setStyleSheet( """ QPushButton[btnType="super"] { background-color: yellow; color: red; } QPushButton[flat="true"] { color: yellow; } """ ) widget.show() app.exec_() С помощью селектора мы избирательно назначили стили на конкретные кнопки. Как получить список всех кастомный свойств? Функция получения списка кастомных свойств отличается от получения дефолтных. def print_widget_dyn_properties(widget): for prop_name in widget.dynamicPropertyNames(): property_name = prop_name.data().decode() property_value = widget.property(property_name) print(f"{property_name}: {property_value}") #tricks #qt
0
14
Регулярно приходится писать и ревьюить код, где используется PySide2-6. Заметил, что в подавляющем большинстве случаев настройка создаваемых базовых виджетов происходит через методы. Думаю, всем знаком такой способ. Простой пример с кнопкой: button = QPushButton("Click Me") button.setMinimumWidth(300) button.setFlat(True) button.setStyleSheet("font-size: 20pt") button.setToolTip("Super Button") button.clicked.connect(lambda: print("Button clicked")) Но есть и альтернативный способ - настройка через свойства. Это просто ключевые аргументы конструктора класса. Хоть они и не указаны в документации как аргументы, но они есть) Этот код делает тоже самое но с помощью Property button = QPushButton( "Click Me", minimumWidth=300, flat=True, styleSheet="font-size: 20pt", toolTip="Super Button", clicked=lambda: print("Button clicked"), ) Где это может быть полезно ▫️ Это выглядит более аккуратно и коротко, уже повод использовать ▫️ Может использоваться в заполнении лейаута, когда нам не нужно никакое другое взаимодействие с виджетом и поэтому сохранять его в переменную не требуется. Например, лейбл или кнопка. widget = QWidget(minimumWidth=400) layout = QHBoxLayout(widget) layout.addWidget(QLabel("Button >", alignment=Qt.AlignRight)) layout.addWidget(QPushButton("Click Me", clicked=lambda: print("Button clicked"))) widget.show() Либо так widget = QWidget(minimumWidth=400) layout = QHBoxLayout(widget) for wd in ( QLabel("Button >", alignment=Qt.AlignRight), QPushButton("Click Me", clicked=lambda: ...) ): layout.addWidget(wd) widget.show() ▫️ Можно хранить настройки в каком-то конфиге или генерировать на лету, после чего передавать как kwargs. kwargs = {"text": "Hello " * 30, "wordWrap": True} my_label = QLabel(**kwargs) Как получить полный список доступных свойств? Эта функция распечатает в терминал все свойства виджета и их текущие значения def print_widget_properties(widget): meta_object = widget.metaObject() for i in range(meta_object.propertyCount()): property_ = meta_object.property(i) property_name = property_.name() property_value = property_.read(widget) print(f"{property_name}: {property_value}") #tricks #qt
0
15
⭐️ Недавно состоялся релиз Python 3.13 Помимо других апдейтов, вот на что я обратил внимание: ◽️Экспериментальный компилятор
⭐️ Недавно состоялся релиз Python 3.13 Помимо других апдейтов, вот на что я обратил внимание: ◽️Экспериментальный компилятор JIT, должен в будущем значительно повысить скорость. Активируется аргументом –enable-experimental-jit ◽️Экспериментальный режим без GIL. Думаю, все знаю что это. Активируется аргументом –without-gil ◽️Удалили ряд стандартных библиотек (PEP-594). Вместе с ними попала под нож lib2to3. Надеюсь больше никому она и не нужна))) ◽️Обновленный REPL с колоризацией. Команда для быстрого запуска docker run --rm -it python:3.13 Либо устанавливаем исталятором↗️ #release
0
16
Когда требуется быстро расшарить файлы в локальную сеть со своего компа можно использовать дефолтный python-сервер. Все решается одной командой. python3 -m http.server Но это бывает неудобным если нужно скачать папку или залить файлы. В этом случае более удобным будет быстрый FTP сервер. Я себе сделал шорткат для поднятия простого FTP сервера без авторизации на базе библиотеки pyftpdlib. Варианты запуска: # на рандомном порту read only python3 -m pyftpdlib # на указанном порту python3 -m pyftpdlib -p 22222 # с доступом на запись python3 -m pyftpdlib -w # с авторизацией python3 -m pyftpdlib -w --user=name --password=123 # полный список аргументолв python3 -m pyftpdlib -h Мой алиас для расшаривания в текущей директории alias ftp="python3 -m pyftpdlib -w -p 22222" Теперь можно подключть FTP соединение как удалённую директорию стандартными средствами OS. В Windows это Add Network Location, в Linux - зависит от дистрибутива. Ищите в разделе Network вашего файлового браузера. Также можно использовать сторонние клиенты, например FileZilla. А здесь подробней про http.server #libs #tricks
0
17
Unofficial Windows Binaries for Python Extension Packages - известная страница с множеством скомпилированных python-библиотек для Windows. Её вёл Christoph Gohlke и любезно нам собирал whl пакеты. Очень часто эа страница помогала и мне и, вероятно, многим из вас. В июне 2022 года из-за отсутствия финансирования проект был закрыт и обновления долго не выходили. Позже и страница была удалена😭 В начале 2023 года Christoph Gohlke создал репозитории на GitHub которые заменили этот "сервис". На его странице в самом верху можно найти несколько ссылок на эти репозитории. В частности репозиторий Pymol-open-source wheels for Python on Windows. Не могу сказать что это уже полноценная замена, кажется новые библиотеки добавляются неспеша, но это уже что-то. Активность можете проследить самостоятельно. А еще там есть эксперементальные сборки для ARM64. PS. Если знаете где есть подобные архивы, поделитесь в коментах. #libs
0
18
⭐️⭐️⭐️ Сегодня 256-й день года, день программиста! Всех причастных — поздравляю ☕️🥸💻 #offtop
⭐️⭐️⭐️ Сегодня 256-й день года, день программиста! Всех причастных — поздравляю ☕️🥸💻 #offtop
0
19
POSIX (Portable Operating System Interface) — это набор стандартов, определяющих интерфейсы для обеспечения совместимости между операционными системами. Данный стандарт поддерживается всеми UNIX-системами (GNU/Linux, macOS, FreeBSD, OpenBSD и другие). А вот в Windows либо частично, либо через подсистемы (такие как WSL). Помимо прочих условий, один из важных моментов этого стандарта - правила синтаксического анализа строк, разбиение на токены. В Python разбиением строки на токены занимается функция shlex.split(), которая имеет один важный аргумент - posix. Этот аргумент определяет, следует ли функции использовать правила синтаксического анализа соответствующие стандарту POSIX, или использовать обратно совместимый, легаси режим. ▫️posix=True В POSIX-совместимом режиме функция shlex.split() будет учитывать переменную окружения IFS (Internal Field Separator) для определения разделителей полей и будет более строго следовать стандарту POSIX. Из строки удаляются неэкранированные кавычки и обратные слеши. ▫️posix=False В легаси режиме используется более старый способ разбиения строк на токены, который будет игнорировать переменную окружения IFS и использовать whitespaces как разделители полей. Теперь смотрим некоторые примеры. import shlex # кавычки text = r'"Do"Not"Separate" \"This\"' shlex.split(text, posix=False) # ['"Do"', 'Not"Separate"', '\\"This\\"'] shlex.split(text, posix=True) # ['DoNotSeparate', '"This"'] # специсимволы text = r'A\tB\nС\fD\vE' shlex.split(text, posix=False) # ['A\\tB\\nС\\fD\\vE'] shlex.split(text, posix=True) # ['AtBnСfDvE'] # обратный слеш text = r"cmd.exe c:\games\mario.exe" shlex.split(text, posix=False) # ['cmd.exe', 'c:\\games\\mario.exe'] shlex.split(text, posix=True) # ['cmd.exe', 'c:gamesmario.exe'] Учитвая, что аргумент posix по умолчанию True, стоит помнить этот факт при обработке строк с Windows-путями! Рекомендую самостоятельно поэксперементировать с этим аргументом! #libs
0
20
При использовании PNG файлов в PySide/PyQt может появляется такой ворнинг libpng warning: iCCP: known incorrect sRGB profile ICC Profile — это файлы, которые содержат информацию о том, как преобразовывать цвета из одного цветового пространства в другое. Они используются для обеспечения точного цветового соответствия между различными устройствами и программами, такими как сканеры, принтеры, мониторы и графические редакторы. sRGB (standard Red Green Blue) — стандартное цветовое пространство, которое используется в цифровой фотографии и веб-дизайне. Указанная выше ошибка говорит о том, что профиль устарел или повреждён. Qt-движок не может его считать. Если у вас множество иконок и иных картинок оформления, то ворнингов будет сыпаться довольно много. Решение — пересохранить файл без профиля, то есть будет использоваться цветовое пространство на усмотрение приложения. from PIL import Image Image.open(input_path).save(output_path, icc_profile=None) from PySide2.QtGui import QImage, QImageWriter image = QImage(input_path) image.setText("icc", "") writer = QImageWriter(output_path) writer.write(image) #tricks
0