Python Заметки
2.31K subscribers
58 photos
2 videos
2 files
212 links
Интересные заметки и обучающие материалы по Python

Контакт: @paulwinex

⚠️ Рекламу на канале не делаю!⚠️

Хештеги для поиска:
#tricks
#libs
#pep
#basic
#regex
#qt
#django
#2to3
#source
#offtop
Download Telegram
Поздравляю всех подписчиц с праздником❗️ 🌹 👠
🔥12👍1
В Linux стандартными средствами можно использовать часть оперативной памяти как диск. Для этого требуется указать тип монтирования tmpfs в команде mount

mount -t tmpfs -o size=5G tmpfs /mnt/ram

Теперь путь /mnt/ram можно использовать как обычный каталог. Для чего это может быть нужно?

▫️ Скорость работы с таким каталогом выше чем многие SSD и тем более HDD.
▫️ Если у вас очень быстрый SSD на NVMe M.2 то такой способ особо не прибавит вам скорости, но поможет сохранить ресурс SSD когда требуется обрабатывать очень много мелких файлов и оперативка позволяет выделить нужный объем.
▫️ Оперативка это энергозависимая память, поэтому выключении питания все файлы безвозвратно теряются. Такой "non persistent" каталог гарантирует удаление временных файлов.

Я написал небольшой скрипт для условного теста и сравнения скорости копирования файлов между SSD и RAM.
Вот мои результаты:

Single File Size: 30.0Gb

ssd > ssd: 0:00:12.850 / 2.3Gb/s
sdd > ram: 0:00:06.453 / 4.6Gb/s
ram > ram: 0:00:06.995 / 4.3Gb/s
ram > sdd: 0:00:06.217 / 4.8Gb/s

Dir size: 32.7Gb, File count: 11127

ssd > ssd: 0:00:15.063 / 2.2Gb/s
sdd > ram: 0:00:08.486 / 3.9Gb/s
ram > ram: 0:00:08.032 / 4.1Gb/s
ram > sdd: 0:00:07.026 / 4.7Gb/s

Скрипт для теста ↗️

На моём железе прирост скорости ~2x. Плюс экономия ресурса SSD.

В Windows такой фишки по умолчанию нет, но обязательно найдутся аналогичные решения

#linux #triks
👍9🔥21
Популярность имеет свои минусы. Чем популярней язык программирования, тем выше его распространённость, а значит найдутся те кто поспешит воспользоваться этим.
С ростом популярности Python всё больше на PyPi появляется вредоносных пакетов. Трояны, стиллеры и доставщики более опасных вредоносов.
Команда PyPi постоянно мониторит подобные случаи но и их возможности достигли предела. В результате сервис временно закрывает возможность заливки новых пакетов и регистрации юзеров.

PyPI new user and new project registrations temporarily suspended

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

Основной тип атаки - рассчёт на опечатку в названии пакета. Если невнимательный программист случайно установит pilow или djangoo, считай что вредонос уже в системе.

Чтобы избежать подобных факапов я рекомендую:

▫️ Всегда работайте в виртуальном окружении, неизвестные проекты устанавливайте внутри контейнеров.
▫️ Используйте файл requirements.txt вместо ручной установки пакетов
▫️ Очень внимательно пишите названия пакетов, а после написания проверьте еще раз. Сверьте с названием из документации.
▫️ После успешных тестов всегда фиксируйте версию пакета. Бывали случаи когда опасный код добавляли в новые версии. К тому же и без этой опасности не рекомендуется ставить по умолчанию последнюю версию.
▫️ Используйте вспомогательные инструменты для проверки безопасности, например https://pyup.io/safety или https://github.com/PyCQA/bandit. Они помогут не только найти опасный код в чужих пакетах, но и ваш код проверит на уязвимости.

Будем надеяться что PyPi переосмыслит методы борьбы с вредоносами, например внедрит ИИ для проверки как симметричный шаг.

#offtop
👍202👎1🤔1
У тех, кто часто работает в терминале, есть привычка вызова особо часто используемых команд. например cd, ls, mc...
Вместо команды exit можно использовать Ctrl+D, и это удобно.

И так уж вышло, что эта привычка невольно у меня включается и при работе в REPL. Для быстрого выхода я жму Ctrl+D, и это работает, но только в Linux. В Windows это совсем не работает, так как там надо нажимать Ctrl+Z. И был бы Windows не такой mustdie если бы этого хватило, но требуется еще нажать Enter (если знаете быстрый выход из REPL на винде, то подсказывайте, я не WinUser). Иногда мне быстрей и привычней вбить exit и нажать Enter, как в bash, но и тут подстава - еще нужны скобки вызова🤬.

В общем, настолько высосанную из пальца проблему надо еще поискать 😆, но я нашел для неё решение!

q = type('q', (object,), {'__repr__': lambda *args: exit()})()

Этот код вставляется в стартап скрипт REPL и создаёт новый объект q. Теперь для выхода из REPL достаточно написать символ q и нажать Enter. Работает одинаково на Linux и Windows.

Как это работает?
▫️ динамически создаётся новый тип объекта с помощью конструкции type(NAME, (BASETYPES,), {ATTRS,})
▫️ в атрибутах создаётся оверрайд метода __repr__, который отвечает за распечатку объекта в REPL
▫️ в этом методе вызывается команда exit()

То есть команда выхода срабатывает как только вы пытаетесь распечатать этот объект в консоли. Именно отображение его репрезентации как объекта а не через не print(), который использует метод __str__.

Аналогично работающий код выглядит так:

class Q:
def __repr__(self):
exit()
q = Q()

Из минусов можно выделить следующее:
▫️ имя q занято, но никто не мешает сделать что-то более уникальное
▫️ Нужно как-то добавлять это в стартап. Тут нам поможет startup script

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

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

#tricks
😁7👍3👎1
Debian 12 не позволяет глобально устанавливать Python пакеты через pip. Не поможет даже sudo.
Такое поведение описано в PEP 668.
Это сделано для минимизации конфликтов версий системных пакетов.
Если вам действительно нужно поставить что-то глобально, используйте
apt install python-packagename
В остальных случаях всегда используйте виртуальное окружение.

#pep
👍18
SQLAlchemy - это один из самых популярных ORM для работы с базами данных из Python.

- поддерживат все популярные базы данных
- не привязана к какому-либо фреймворку (как, например, Django ORM)
- поддерживает асинхрон
- позволяет удобно (питонично) делать довольно сложные SQL запросы

15 июля вышла первая версия из ветки 2.0 и это хорошйи повод изучить эту библиотеку если еще не начали.

Подобрал вам ресурсы для изучения:

- Вебинар и урок про новую SQLAlchemy2.0 от Mike Bayer (автор sqlalchemy и alembic ) с онлайн конференции pythonwebconf:

https://www.youtube.com/watch?v=Uym2DHnUEno

- Для тех кто на английском не очень, есть онлайн книга на руссом от https://t.iss.one/massonnn_yt.
А так же видео версия:

https://www.youtube.com/watch?v=leeC0fpAY-E&list=PLN0sMOjX-lm5Pz5EeX1rb3yilzMNT6qLM

Лично я использую алхимию в связке с FastAPI и пока всё устраивает

#tricks #libs
👍22
Как в Linux отправить картинку на печать из Python? Это можно сделать с помощью CUPS - Common Unix Printing System

▫️ Ставим зависимости

sudo apt install -y libcups2-dev python3-dev gcc

▫️ Устанавливаекм библиотеку-обертку

pip install pycups

▫️ Печатаем

import cups
# устанавливаем коннект
conn = cups.Connection()
# получаем список принтеров
printers = conn.getPrinters()
print(printers)
printer_name = list(printers.keys())[0]
# отправляем на печать
conn.printFile(printer_name, image_path, "Image Print", {})

#libs
👍8
This media is not supported in your browser
VIEW IN TELEGRAM
Прошлый пост про печать появился неспроста!
Недавно мне потребовалось напечатать большую версию чертежа. Нужен был инстурмент, аналогичный многостраничной печати в CorelDraw но под Linux.
Поэтому я решил ... чтобывыдумали???... да, сделать свой велосипед 😂

И вот что у меня вышло.

➡️ Tile Printer

▫️Интерактивное позиционирование картинки
▫️Отправка на печать или сохранение в файлы
▫️Настройка отступов
▫️Можно указать DPI

ЗЫ. Не судите строго, сделано всё за 1 день.
ЗЗЫ. Да, я гуглил аналоги. Самый советуемый инструмент posterazor не подошел по функционалу. Остальные не стоят внимания.

#source
8🤩3
Как проверить является ли директория пустой?

Самый простой способ:

if os.listdir(path):
...

Тоже самое с pathlib

p = Path(path)
if list(p.iterdir()):
...

В первом случае функция os.listdir возвращает полный список файлов. Нам остаётся проверить есть ли там что-либо.
Во втором случае мы получаем генератор, который под капотом использует тот же listdir.

Теперь представим что в директории 10к файлов

for i in range(10000):
Path(f'/tmp/test/test{i}.txt').touch()

Не сказать, что при наличии SSD это проблема, но когда таких операций много, мы начинаем терять время, особенно с pathlib.

import timeit
test_path = '/tmp/test'
count = 1000

>>> timeit.timeit('list(os.listdir(p))', setup=f'import os;p="{test_path}"', number=count)
2.281363710993901
>>> timeit.timeit('list(p.iterdir())', setup=f'from pathlib import Path;p=Path("{test_path}")', number=count)
5.6957218300012755

То есть мы получаем список всех 10к файлов просто чтобы узнать что там есть файлы. Хотя нам надо узнать есть ли по указанному пути хотя бы один файл.
Для того чтобы ускорить проверку лучше воспользоваться функцией os.scandir(). Она работает на много быстрей и возвращает итератор с объектами os.DirEntry.
Чтобы узнать есть ли в директории хоть один файл достаточно использовать функцию next()

next(os.scandir(path))

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

if next(os.scandir(path), None):
...

Либо используем функцию any(), так как она завершится сразу после нахождения первого файла или если итератор пуст.

if any(os.scandir(path)):
...

Сравним скорость
>>> timeit.timeit('next(os.scandir(p), None)', setup=f'import os;p="{test_path}"', number=count)
0.2183076049986994
>>> timeit.timeit('any(os.scandir(p))', setup=f'import os;p="{test_path}"', number=count)
0.21016486900043674

#tricks
👍164
⭐️ Встречаем релиз 3.12

Из того что мне приглянулось:
▫️ Всё ближе sub-interpreters, на С уже можно пробовать. В Python-коде будет в следующем релизе.
▫️ Наконец закончится возня с кавычками в f-string
▫️ Говорят, хорошо ускорили async код.

➡️ Остальные подробности читаем здесь


#release
🔥5👍2
Функция dir() - удобна для получения списка атрибутов у любого объекта.

Ранее я писал про функцию __dir__() в модуле (не путайте её с переменной __all__(), которая указывает список объектов для импорта если встречается конструкция from module import *).

Скорее всего вы уже знаете как использовать функцию dir(). Любой объект может реализовать метод __dir__() чтобы указать список имеющийхся и динамических атрибутов. И функция dir() поможет получить список этих атрибутов.

>>> dir(str)
['__add__', '__class__', '__contains__', ...]

У этой функции есть еще один способ применения. Её можно вызвать без аргумента, и в таком случае она вернёт список имён в текущем неймспейсе.

>>> dir()
['__builtins__', '__doc__', '__file__', ...]

>>> def test():
>>> x = 1
>>> print(dir())
>>> test()
['x']

#basic #tricks
👍7
Почему проект Qt.py до сих пор не добавил обёртку PySide6?

Данный модуль используется в DCC и смежных инструментах. А учитывая стандартны отрасли, описанные на VFX Platform в 2023м году стандартном всё еще является Qt5. Переход на Qt6 запланирован на 2024й. Скорее всего к тому времени подтянется поддержка 6й ветки (но лучше бы заранее).

В своих проектах с Qt6 можете исползовать альтернативный проект qtpy, который уже поддерживает Qt6 но не поддерживает старые версии. Модуль поддерживает PyQt5, PySide2, PyQt6 и PySide6.

#libs
👍3
Удобный сервис для генерации команд ffmpeg.
➡️ https://alfg.dev/ffmpeg-commander/

Отлично подходит для изучения ffmpeg и для быстрых набросков команды.

А так же, на заметку, python-обертка

#tools #libs
👍123🔥2
Пока команда разрабов Python понемногу наращивает скорость работы интерпретатора, новый язык программирования Mojo с заявкой на замену Python тихо пилит свои первые релизы. Уже сейчас прирост в CPU рассчётах в 10к раз! Можно скачать и сравнить скорость, или посмотреть что пишут другие.

Как по мне, это выглядит как еще одна версия интерпретатора, хотя, это и не совсем так. Похоже на тот же cython - нативная поддержка дефолтного кода Python плюс свои фишки синтасиса сверху. Всё же надежда на прорывные технологии остаётся, Подождём, увидим...

Забавно, что в минимальных требованиях 8Гб оперативки 😧

#libs #offtop
Что позволяет делать f-strings в 3.12.

▫️можно использовать одинаковые кавычки во всём выражении
▫️можно добавлять переносы для многострочного выражения
▫️можно использовать символ новой строки (эта проблема неактуальна)
>>> print(f"{"\n".join(
>>> ["1","2","3",
>>> f"{
>>> f"{2+2}"
>>> *(2+2)
>>> }"
>>> ]
>>> )}")
1
2
3
4444

#tricks #libs
👍12
Варианты распаковки контейнеров по отдельным переменным

Обычная распаковка по точному количеству
data = [1, 2, 3, 4, 5]
v1, v2, v3, v4, v5 = data

Распаковка с неизвестным количество но не меньше чем N
v1, *_ = data
v1, *_, v4, v5 = data

Если точно знаете позицию нужного объекта в списке, включая вложенные списки, то достать его можно двумя способами
Через индекс:
data = [[1]]
v1 = data[0][0]

Через распаковку со скобками:
data = [[1]]
(v1, ), = data

data = [[[1]]]
((v1,), ), = data

Еще примеры распаковки вложенных объектов
data = [[1, 2], [3, 4], [5, 6]]
(v1, v2), (v3, v4), (v5, v6) = data
(v1, v2), *_, (v5, *_) = data

#tricks
🔥16👍6
Если вы занимаетесь веб разработкой то знаете, что для оформления UI принято использовать шрифтовые иконки.
Самые популярные наборы это, конечно же, FontAwesome и MaterialDesign

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

https://github.com/spyder-ide/qtawesome

▫️добавление любых иконок из популярных наборов иконок
▫️выбор цвета иконки
▫️изменение цвета для активного виджета
▫️поддержка анимации
▫️создание видежта иконки

Пример создания иконки

import qtawesome as qta
icon = qta.icon('fa5.flag')


#libs
👍7
Где можно применять моржовый (walrus) оператор? (Py3.8+)

Очевидное назначение моржового оператора - сократить количество кода. Сделать присвоение значения переменной и его использование в одно действие. Чаще всего используется в конструкциях if и while

if match := pattern.search(data):
print(match.groups())

while chunk := file.read(1024):
process(chunk)


Можно ли использовать его внутри f-string?

print(f'{x:=10}')
# NameError: name 'x' is not defined


Это синтаксис форматирования а не walrus. Чтобы превратить выражение в walrus используем скобки

print(f'{(x:=15)}')
# '15'
print(x)
# 15


Получается, что скобки помогут использовать walrus не только с if, while, match и тд.

Пример не самого очевидного присвоения значений переменным

x = (y := 1, 2)
print(x)
print(y)
# (1, 2)
# 1


Вызов функции тоже может быть использован как скобки для walrus

def get(): return 2
def do_it(x, y): return x + y

x = do_it(y := get(), y+3)
print(x, y)
# 7 2


Два "моржа" на одном пляже в одной строке

def compute(x): return x*2
def get_value(): return 1

if z := compute(x := get_value()):
print(f"compute({x}) = {z}")
else:
print(f"{x} is not valid value")
# compute(1) = 2


В следующем примере мы экономим не только код но и количество расчётов

list1 = [1, 2, 3, 4, 5]
# без walrus
list2 = [x*2 for x in list1 if x*2 % 15 == 0]
# c walrus
list2 = [(n := x*2) for x in list1 if n % 15 == 0]


Создание списка выполняется последовательно, поэтому можно объявить переменную в первом элементе и использовать в остальных

f = lambda v: v*2
[y := f(1), y**2, y**3]
# [2, 4, 8]


Более страшный пример с созданием lambda через walrus

[y := (f := lambda x, i: x*i)(3, 10), z:=f(y, 20), f(z, 30)]
# [30, 600, 18000]

не делайте так

Экономим один вызов lower() в простом выражении

is_palindrome = (w := word.lower()) == w[::-1]


И ещё пример экономии места в файле и времени CPU

try:
10 / 0
except Exception as err:
logger.log(message := f"Error, {err}!")
send_report(message)


А еще не будет ошибкой синтаксиса если использовать walrus перед return.

def calculate(a, b):
return result := a * b


Но, по очевидным причинам, смысла в этом нет 😄

#triks
👍16🤯31
Awesome Python Typing

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

Есть ссылка на надавно вышедшую SQLAlchemy2, так что актуальность поддерживается.

Странно что всё еще нет в списке Ruff. Хотя, в Issues уже добавили запрос. Но автор не уверен что эта тулза подходит для его списка.

#libs
👍4
Всех, кто в теме, с праздником! 🎉🚀⭐️
🔥17👍43