Все знают синтаксический сахар с операторами
Где под капотом он превращается в
Останется ли переменная
Конечно нет, это же неизменяемый тип
Теперь провернём тоже самое со списком
Ожидаемо работает так же, ведь мы создали новую переменную.
А теперь попробуем иначе:
И, внезапно, это работает не так как с int, со списками оператор
То же самое будет с
Следует помнить о такой важной разнице!
(Особенно на собесах 😉)
#tricks
+=, -= и тдx += 1
Где под капотом он превращается в
x = x + 1
Останется ли переменная
х той же переменной после +=?Конечно нет, это же неизменяемый тип
x = 1
print(id(x))
# 135373664533280
x += 1
print(id(x))
# 135373664533312
Теперь провернём тоже самое со списком
ls = [1, 2]
print(id(ls))
# 135373622585344
ls = ls + [3]
print(id(ls))
# 135373619036608
Ожидаемо работает так же, ведь мы создали новую переменную.
А теперь попробуем иначе:
ls = [1, 2]
print(id(ls))
# 135373622585344
ls += [3]
print(id(ls))
# 135373622585344
print(ls)
# [1, 2, 3]
И, внезапно, это работает не так как с int, со списками оператор
+= работает как extend()!То же самое будет с
*=, объект останется тем же.ls = [1, 2]
print(id(ls))
# 135373622585344
ls *= 2
print(id(ls))
# 135373622585344
print(ls)
# [1, 2, 1, 2]
Следует помнить о такой важной разнице!
#tricks
👍14❤1
Не запуская код определите, что покажет терминал если выполнить следующее:
Ответ:Несмотря на то, что ваш IDE покажет ошибку, ошибки не будет. Распечатается "c"
Объяснение:
1. Mangling
За это отвечает механизм mangling - искажение имени. Так работают приватные атрибуты классов.
При создании атрибута по правилу: минимум 2 "_" в начале и максимум 1 "_" в конце" имя автоматически становится вида _{classname}{attr}
В нашем случае атрибутов класса не создается, но это не отменяет Mangling при обращении к другим объектам внутри класса.
2. Обращение к атрибуту
Когда внутри класса происходит обращение к любому объекту с именем по указанному выше правилу, его имя на уровне байт кода также преобразуется.
3. Поиск
Далее происходит поиск такой переменной по неймспейсам в порядке LEGB - Local, Enclosing, Global, Built-in.
И не трудно догадаться что мы находим нужный атрибут в Global, В итоге получаем результат!
Проверить можно так:
Либо удалите переменную
Как думаете, это норма или баг?
#tricks
_A__b = 'c'
class A:
def get(self):
return __b
print(A().get())
Ответ:
Объяснение:
1. Mangling
За это отвечает механизм mangling - искажение имени. Так работают приватные атрибуты классов.
При создании атрибута по правилу: минимум 2 "_" в начале и максимум 1 "_" в конце" имя автоматически становится вида _{classname}{attr}
В нашем случае атрибутов класса не создается, но это не отменяет Mangling при обращении к другим объектам внутри класса.
2. Обращение к атрибуту
Когда внутри класса происходит обращение к любому объекту с именем по указанному выше правилу, его имя на уровне байт кода также преобразуется.
3. Поиск
Далее происходит поиск такой переменной по неймспейсам в порядке LEGB - Local, Enclosing, Global, Built-in.
И не трудно догадаться что мы находим нужный атрибут в Global, В итоге получаем результат!
Проверить можно так:
import dis
dis.dis(A.get)
# 4 RESUME 0
#
# 5 LOAD_GLOBAL 0 (_A__b)
# RETURN_VALUE
Либо удалите переменную
_A__b и запустите еще раз, поулчите ошибку:NameError: name '_A__b' is not defined
Как думаете, это норма или баг?
#tricks
❤5😢3
В Gunicorn добавили ASGI. Пока что beta.
То есть теперь вместо "gunicorn воркеры + uvicorn ранеры" будет всё из одной библиотеки? Коненчо, если скорость не будет драматически ниже.
#libs
gunicorn myapp:app --worker-class asgi
То есть теперь вместо "gunicorn воркеры + uvicorn ранеры" будет всё из одной библиотеки? Коненчо, если скорость не будет драматически ниже.
#libs
GitHub
GitHub - benoitc/gunicorn: gunicorn 'Green Unicorn' is a WSGI HTTP Server for UNIX, fast clients and sleepy applications.
gunicorn 'Green Unicorn' is a WSGI HTTP Server for UNIX, fast clients and sleepy applications. - benoitc/gunicorn
🔥3
Потоковая обработка часто встречается при работе с большими файлами или когда данные приходят частями. В Python есть множество инструментов для работы с такими данными. Самый известный - итератор файла по строкам. В веб-приложениях это стандарт для передачи файлов. Далее приведу несколько примеров.
Чтение файлов
Это позволяет нам читать текстовый файл по строкам не загружая всё в память.
Конечно, если позволяет формат данных. С JSON такое не сработает (ijson может в этом помочь).
Запись файла чанками
Частные случаи есть в разных библиотеках. Например DictWriter и DictReader из модуля csv позволяет работать с конкретным форматом данных а не просто текст.
Отдельно интересен ZipFile, позволяющий "открыть" файл сразу внутри архива и записывать его частями
Создание хеша для большого файла
Сжатие данных в файл отдельными чанками
Чтение с записью в файл
Подсчет объектов из стрима. Добавление обновляет счетчики.
Это не все доступные примеры, их еще много. Каждый из них позволяет обрабатывать данные из потока не ожидая весь набор и не загружая их в оперативку.
Это очень полезная техника, которую я призываю использовать по назначению!
#tricks #libs
Чтение файлов
with open('huge-file.txt') as file:
for line in file:
process_line(line)Это позволяет нам читать текстовый файл по строкам не загружая всё в память.
Конечно, если позволяет формат данных. С JSON такое не сработает (ijson может в этом помочь).
Запись файла чанками
with open('file-to-save.txt',
'w') as file:
for line in iter_data():
file.write(line)Частные случаи есть в разных библиотеках. Например DictWriter и DictReader из модуля csv позволяет работать с конкретным форматом данных а не просто текст.
import csv
with open('data.csv', 'r') as file:
reader = csv.DictReader(file)
for row in reader:
print(row)
with open('data.csv', 'a',
newline='') as f:
writer = csv.DictWriter(f,
fieldnames=['col1', 'col2']
)
for row in iter_objects():
writer.writerow(row)
Отдельно интересен ZipFile, позволяющий "открыть" файл сразу внутри архива и записывать его частями
import zipfile as zf
with zf.ZipFile(
'archive.zip',
'w',
compression=zf.ZIP_DEFLATED) as zf:
with zf.open(
'large_data.bin',
mode='w') as in_file:
with open(
'large_data.bin',
'rb') as source:
for chunk in iter(
lambda: source.read(1024),
b''):
in_file.write(chunk)
Создание хеша для большого файла
import hashlib
sha256 = hashlib.sha256()
with open(
'large-file.bin',
'rb') as f:
for block in iter(
lambda: f.read(1024), b''
):
sha256.update(block)
hash_sum = sha256.hexdigest()
Сжатие данных в файл отдельными чанками
import gzip
with gzip.open('data.gz', 'wb') as f:
for bin_chunk in iter_bin_data():
f.write(bin_chunk)
Чтение с записью в файл
with gzip.open('data.gz', 'rb') as f_in:
with open(
'extracted_data.txt',
'wb') as f_out:
for chunk in iter(
lambda: f_in.read(1024),
b''):
f_out.write(chunk)Подсчет объектов из стрима. Добавление обновляет счетчики.
from collections import Counter
c = Counter()
for data in iter_objects():
c.update(data)
Это не все доступные примеры, их еще много. Каждый из них позволяет обрабатывать данные из потока не ожидая весь набор и не загружая их в оперативку.
Это очень полезная техника, которую я призываю использовать по назначению!
#tricks #libs
👍12
reload_flag=""
if [[ -n "${DEBUG}" ]]; then
reload_flag="--reload"
fi
if [[ -n "${WORKER_COUNT}" ]]; then
workers=${WORKER_COUNT}
else
workers=2
fi
gunicorn --workers ${workers} \
--bind 0.0.0.0:8000 \
${reload_flag} main.wsgi
Писали такие конструкции чтобы проверить наличие флага и сформировать команду правильно?
На самом деле можно сделать тоже самое проще. Для этого используются операторы условной подстановки, доступные в оболочках семейства POSIX.
:- для установки значений по умолчанию${WORKER_COUNT:-2}Если переменная не объявлена, то будет дефолтное значение 2.
:+ подставляет указанный текст, если переменная не пуста${DEBUG:+--reload}Если что-то есть в переменной то распечатается текст после символа
+, в противном случае - ничего. Удобно для опциональных флагов, как в нашем примере.Итого наш скрипт может выглядеть так:
gunicorn --workers ${WORKER_COUNT:-2} \
--bind 0.0.0.0:8000 \
${DEBUG:+--reload} main.wsgiЕсть еще два оператора.
:= не только подставить дефолтное значение, но и присвоить его переменной, если она пуста# никаких переменных еще нет
VAL1=${VAL2:=hello}
# теперь доступны обе
echo $VAL1 $VAL2
# hello hello
:? остановить выполнение с ошибкой, если переменной нет.echo ${MISS:?is required}
bash: MISS: is requiredКод выхода будет 1.
#tricks #linux
👍5
Windows 11 становится всё менее дружелюбна к юзерам а порой и вовсе не юзабельной:
▫️ постоянные ломающие апдейты которые не дают загрузить систему, откатить ломающие апдейты, и давно уже удаляют файлы пользователей без спроса. Тенденция в целом уже достаточно давно, включая глобальные сбои и другие неприятности.
▫️ навязчивое продвижение AIшпионов агентов повсюду в системе которых никто не просил.
▫️ всё больше ресурсов ВАШЕГО компа работают не для вас, а в угоду Microsoft. Мелкомягкие официально предлагают купить железо помощней (чтобы они и дальше могли половину мощности использовать по своему усмотрению) а оно что-то не покупается. Рядовой юзер не понимает зачем менять комп который и так норм работает. А глядя на текущие цены на память наступает ощущение что с этим миром что-то не так.
▫️ люди булшитят винду и активно продвигают переход на Linux порой называя винду кучей слопа или даже вирусом, похищающим файлы с целью выкупа (они реально после аплоада и удаления с локала отключают доступ к файлам и требуют купить подписку). А сам Microsoft переименован в Microslop. Появляются даже тулзы для очистки системы от этого слопа.
▫️ Microsoft уже не скрывает, что ваши данные уже не ваши, даже зашифрованные, ибо ваши пароли давно уже хранятся где надо и доступны кому надо.
▫️ При всех этих факапах они закрыли поддержку Windows 10 не давая возможности откатиться на что-то более стабильное.
То есть сами Microsoft стали катализатором поиска альтернатив.
Сам я уже на Linux уже более 7 лет как на основной системе, дома винда есть только в виртуалке для тестов клиентского софта. Расскажите, как у вас обстоят дела на винде? Вы пользуетесь системой или боретесь с ней?
#offtop
▫️ постоянные ломающие апдейты которые не дают загрузить систему, откатить ломающие апдейты, и давно уже удаляют файлы пользователей без спроса. Тенденция в целом уже достаточно давно, включая глобальные сбои и другие неприятности.
▫️ навязчивое продвижение AI
▫️ всё больше ресурсов ВАШЕГО компа работают не для вас, а в угоду Microsoft. Мелкомягкие официально предлагают купить железо помощней (чтобы они и дальше могли половину мощности использовать по своему усмотрению) а оно что-то не покупается. Рядовой юзер не понимает зачем менять комп который и так норм работает. А глядя на текущие цены на память наступает ощущение что с этим миром что-то не так.
▫️ люди булшитят винду и активно продвигают переход на Linux порой называя винду кучей слопа или даже вирусом, похищающим файлы с целью выкупа (они реально после аплоада и удаления с локала отключают доступ к файлам и требуют купить подписку). А сам Microsoft переименован в Microslop. Появляются даже тулзы для очистки системы от этого слопа.
▫️ Microsoft уже не скрывает, что ваши данные уже не ваши, даже зашифрованные, ибо ваши пароли давно уже хранятся где надо и доступны кому надо.
▫️ При всех этих факапах они закрыли поддержку Windows 10 не давая возможности откатиться на что-то более стабильное.
То есть сами Microsoft стали катализатором поиска альтернатив.
Сам я уже на Linux уже более 7 лет как на основной системе, дома винда есть только в виртуалке для тестов клиентского софта. Расскажите, как у вас обстоят дела на винде? Вы пользуетесь системой или боретесь с ней?
#offtop
Telegram
Чёрный Треугольник
☝🏻Январское обновление Windows 11 ломает ПК пользователей
Microsoft официально признала критическую ошибку в обязательном обновлении безопасности KB5074109, которое вышло 13 января 2026 года для Windows 11 версий 24H2 и 25H2.
После установки патча часть…
Microsoft официально признала критическую ошибку в обязательном обновлении безопасности KB5074109, которое вышло 13 января 2026 года для Windows 11 версий 24H2 и 25H2.
После установки патча часть…
👍4
А что происходит на противоположном фронте?
Вы, вероятно, слышали, что 2026 год называют годом Linux на десктопе (в каких-то узких кругах - годом гейминга на Linux). Всё потому, что экосистема Linux постепенно становится более дружелюбной для обычных десктоп-юзеров (в том числе привыкших к Windows), и не только!
▫️ всё чаще появляются Linux дистрибутивы визуально похожие на Windows (или даже лучше), и множество видео с советами какой дистрибутив попробовать новичкам.
▫️ обновления ядра и любых пакетов в экосистеме Linux всегда привносят оптимизацию и удобство и поддержку свежего железа (привет винде с её обратной тенденцией). Например грядущая версия 7.0, опять с множеством приятных мелочей.
▫️ после 10 лет с последего релиза версии 5 окружение KDE Plasma получила мажорный апдейт версии 6 и активно развивается (уже доросла до 6.5). GNOME тоже не спит и готовит версию 50.
▫️ в Wine добавили патч позволяющий устанавливать продукты Adobe на Linux. Для кого-то это был последний рубеж?😏
▫️ Proton активно развивается, да так, что через эту прослойку игры работают даже быстрей чем нативно на винде.
▫️ с каждым релизом Wine и Proton поддерживается всё больше игр, что можно отслеживать на ProtonDB, и даже случаются бусты производительности.
▫️ Я сам на днях на виндобук поставил ChacyOS после чего игры, которые тянули гдето в 5-10 FPS, стали играбельными! Подтверждено личным опытом! Кстати, есть несколько дистрибутивов заточенные именно под игры.
▫️ Valve выпускают новую пачку железок которые (предположительно) порвут рынок гейминга (как и в прошлый раз) и (определнно точно) работают на Linux. Именно Valve вливает ресурсы в Linux в целом и в Proton в частности.
▫️ Госсектор разных стран давно уже мигрирует на opensource, так как нет доверия системе которая может одномоментно неконтролируемо массово рухнуть или быть удаленно заблокированной (в том числе по политическим причинам).
И ниже небольшой опрос - какая у вас операционка основная?
#offtop #linux
Вы, вероятно, слышали, что 2026 год называют годом Linux на десктопе (в каких-то узких кругах - годом гейминга на Linux). Всё потому, что экосистема Linux постепенно становится более дружелюбной для обычных десктоп-юзеров (в том числе привыкших к Windows), и не только!
▫️ всё чаще появляются Linux дистрибутивы визуально похожие на Windows (или даже лучше), и множество видео с советами какой дистрибутив попробовать новичкам.
▫️ обновления ядра и любых пакетов в экосистеме Linux всегда привносят оптимизацию и удобство и поддержку свежего железа (привет винде с её обратной тенденцией). Например грядущая версия 7.0, опять с множеством приятных мелочей.
▫️ после 10 лет с последего релиза версии 5 окружение KDE Plasma получила мажорный апдейт версии 6 и активно развивается (уже доросла до 6.5). GNOME тоже не спит и готовит версию 50.
▫️ в Wine добавили патч позволяющий устанавливать продукты Adobe на Linux. Для кого-то это был последний рубеж?😏
▫️ Proton активно развивается, да так, что через эту прослойку игры работают даже быстрей чем нативно на винде.
▫️ с каждым релизом Wine и Proton поддерживается всё больше игр, что можно отслеживать на ProtonDB, и даже случаются бусты производительности.
▫️ Я сам на днях на виндобук поставил ChacyOS после чего игры, которые тянули гдето в 5-10 FPS, стали играбельными! Подтверждено личным опытом! Кстати, есть несколько дистрибутивов заточенные именно под игры.
▫️ Valve выпускают новую пачку железок которые (предположительно) порвут рынок гейминга (как и в прошлый раз) и (определнно точно) работают на Linux. Именно Valve вливает ресурсы в Linux в целом и в Proton в частности.
▫️ Госсектор разных стран давно уже мигрирует на opensource, так как нет доверия системе которая может одномоментно неконтролируемо массово рухнуть или быть удаленно заблокированной (в том числе по политическим причинам).
И ниже небольшой опрос - какая у вас операционка основная?
Ни к чему не призываю, ничего не советую! Просто подмечаю тенденцию и хочется узнать мнения из первых рук 😉
Знаю, что Linux тоже не идеален, знаю что каждой задаче - свой инструмент. Но это не тема поста, так что можно без холиваров)
#offtop #linux
Хабр
Почему 2026-й станет годом десктопного Linux + интересные дистрибутивы внутри
Есть все признаки того, что 2026 год наконец-то станет годом десктопного Linux . Ниже — разбор причин этого сдвига и обзор перспективных дистрибутивов для игр, максимальной производительности и...
Ваша рабочая система?
Final Results
25%
Windows навсегда!
10%
Думаю попробовать Linux...
36%
Linux наше всё!
23%
Я на маке)
6%
У меня нет компа(
Вы до сих пор используете в проекте "магические" строки?😖
Где тут проблема?
🔸 Если
🔸 Напишете
🔸 Вам очень повезет, если в проекте нет такой же строки но с другим смыслом
Как делать правильно?
Используем модуль
Почему это лучше:
▫️Теперь это не строка а объект
▫️ IDE сможет подсказать какие статусы существуют, вам не нужно лезть в документацию или базу
▫️ Единый источник истины. Изменяем в одном месте вместо поиска на всему проекту
▫️ Типизация - наше всё, mypy умеет с этим работать
▫️ Читаемость кода повышается. Ведь читаем мы его чаще чем пишем
▫️ Автоматическая валидация допустимых значений в моделях Pydantic
#tricks
@dataclass
class Task:
status: str
...
def create_pending_task(data: dict) -> Task:
task = Task(**data)
task.status = "pending" # < магическая строка
return task
Где тут проблема?
🔸 Если
"pending" изменится на "wait", вам придется искать это слово по всему проекту🔸 Напишете
panding вместо pending и баг вылезет только в рантайме в непредсказуемом месте🔸 Вам очень повезет, если в проекте нет такой же строки но с другим смыслом
Как делать правильно?
Используем модуль
enumfrom enum import StrEnum
class TaskStatus(StrEnum):
PENDING = "pending"
RUNNING = "running"
COMPLETED = "completed"
@dataclass
class Task:
status: TaskStatus
...
def create_pending_task(data: dict) -> Task:
task = Task(**data)
task.status = TaskStatus.PENDING
return task
Почему это лучше:
▫️Теперь это не строка а объект
▫️ IDE сможет подсказать какие статусы существуют, вам не нужно лезть в документацию или базу
▫️ Единый источник истины. Изменяем в одном месте вместо поиска на всему проекту
▫️ Типизация - наше всё, mypy умеет с этим работать
▫️ Читаемость кода повышается. Ведь читаем мы его чаще чем пишем
▫️ Автоматическая валидация допустимых значений в моделях Pydantic
#tricks
👍14❤5👎2
Почему в прошлом посте я использовал
Всё просто, дефолтный
Как видите, приходится вызывать
Для примера из прошлого поста это выглядело бы так:
Когда не стоит использовать
- когда нужно явное отличие значений энума от строки
- когда в проекте уже используется обычный
#tricks
StrEnum а не Enum?Всё просто, дефолтный
Enum не поддерживает нативное сравнение с нужным нам типом.from enum import Enum
class DefaultEnum(Enum):
KEY = "value"
"value" == DefaultEnum.KEY # False
"value" == DefaultEnum.KEY.value # True
Как видите, приходится вызывать
.value, что неудобно в некоторых случаях и более многословно. StrEnum это исправляет:from enum import StrEnum
class StringEnum(StrEnum):
KEY = "value"
"value" == StringEnum.KEY # True
Для примера из прошлого поста это выглядело бы так:
if task.status == TaskStatus.PENDING:
...
Точно так же работает и IntEnum.
StrEnum появился в версии 3.11, для более ранних использовали комбинацию MyEnum(str, Enum), что не тоже самое.StrEnum правильно создает значения с функцией auto(). Сочетание str+Enum создает числа, но в виде строк. Приходится явно писать строки. Сделал пару примеров для сравнения↗️Когда не стоит использовать
StrEnum:- когда нужно явное отличие значений энума от строки
- когда в проекте уже используется обычный
Enum#tricks
Gist
py-enum-examples.py
GitHub Gist: instantly share code, notes, and snippets.
👍9
Оператор pipe позволяет писать более компактный код, реализуя логику объединения данных (Union).
Важно помнить, что его поведение зависит от контекста.
Побитовые операции (логическое OR)
Самое главное - не путать с оператором or, это другое!
Объединение множеств
Слияние словарей
Аннотации типов, заменяет Union
Допустимо использовать в isinstance или issubclass
Паттерн-матчинг
Так же нашел библиотеку pipe которая добавляет еще много возможностей. Рекомендую ознакомиться ;)
#basic
Важно помнить, что его поведение зависит от контекста.
Побитовые операции (логическое OR)
result = 5 | 3
# 5 (0101) | 3 (0011) = 7 (0111)
Самое главное - не путать с оператором or, это другое!
Объединение множеств
set_a = {1, 2, 3}
set_b = {3, 4, 5}
set_c = set_a | set_b
# {1, 2, 3, 4, 5}
set_c |= {5, 6}
# {1, 2, 3, 4, 5, 6}Слияние словарей
dict_1 = {"a": 1, "b": 2}
dict_2 = {"b": 3, "c": 4}
merged = dict_1 | dict_2
# {'a': 1, 'b': 3, 'c': 4}
merged |= {"d": 5}
# {'a': 1, 'b': 3, 'c': 4, 'd': 5}Аннотации типов, заменяет Union
def process_data(value: int | str) -> None:
print(value)
Допустимо использовать в isinstance или issubclass
isinstance(3, int | float)
# True
Паттерн-матчинг
status_code = 404
match status_code:
case 200 | 201 | 204:
print("OK")
case 400 | 404 | 500:
print("ERROR")
Для использования в своих классах требуется переопределить метод __or__
Так же нашел библиотеку pipe которая добавляет еще много возможностей. Рекомендую ознакомиться ;)
#basic
GitHub
GitHub - JulienPalard/Pipe: A Python library to use infix notation in Python
A Python library to use infix notation in Python. Contribute to JulienPalard/Pipe development by creating an account on GitHub.
❤4
Еще одно применение пайпов - в контексте с Enum.
Но для этого нужен специальный Enum основанный на типе Flag.
В связке с auto он генерирует битовые маски, которые впоследствии можно использовать с оператором
Теперь мы можем комбинировать их через пайп
Можно делать проверки через
Либо через
Оператор
Можно заранее создать комбинацию.
Flag более изолирован. Он не равен числу напрямую, что защищает от случайных ошибок в логике.
#tricks
Но для этого нужен специальный Enum основанный на типе Flag.
В связке с auto он генерирует битовые маски, которые впоследствии можно использовать с оператором
|from enum import Flag, auto
class Perm(Flag):
READ = auto() # 1 (0001)
WRITE = auto() # 2 (0010)
EXECUTE = auto() # 4 (0100)
DELETE = auto() # 8 (1000)
Теперь мы можем комбинировать их через пайп
admin_perms = Perm.READ | Perm.WRITE | Perm.EXECUTE
user_perms = Perm.READ | Perm.EXECUTE
print(admin_perms)
# <Perm.READ|WRITE|EXECUTE: 7>
Можно делать проверки через
in (возвращает bool)if Perm.READ in admin_perms:
print("Success!")
Либо через
& (возвращает совпадение либо 0)print(Perm.READ & admin_perms)
# <Perm.READ: 1>
print(Perm.WRITE & user_perms)
# <Perm: 0>
Оператор
~ инвертирует все флагиprint(~admin_perms)
#<Perm.DELETE: 8>
Можно заранее создать комбинацию.
class Perm(Flag):
READ = auto() # 1 (0001)
WRITE = auto() # 2 (0010)
EXECUTE = auto() # 4 (0100)
DELETE = auto() # 8 (1000)
RW = READ | WRITE
mode = Perm.READ
print(mode & Perm.RW)
# <Perm.READ: 1> (True)
print(mode & Perm.EXECUTE)
# <Perm: 0> (False)
Flag более изолирован. Он не равен числу напрямую, что защищает от случайных ошибок в логике.
#tricks
❤7👍5👎1
Все паблики облетела новость о покупке Astral. Мнения бытуют разные, так что мне сложно даже предполагать к чему это приведёт.
Сегодня всё так быстро меняется и происходит то, во что раньше бы никто не поверил! Вобщем, будем надеятся.
https://openai.com/index/openai-to-acquire-astral/
#offtop
Сегодня всё так быстро меняется и происходит то, во что раньше бы никто не поверил! Вобщем, будем надеятся.
https://openai.com/index/openai-to-acquire-astral/
#offtop
OpenAI
OpenAI to acquire Astral
Accelerates Codex growth to power the next generation of Python developer tools
🔥1
Мы используем Makefile думая, что нет альтернатив, что это стандарт и всё такое.
Но make это не запускалка команд, а система сборки. Мы фактически используем его не по назначению.
И на самом деле альтернатива есть! Некоторое время назад я открыл для себя прекрасный инструмент - just. Он решает все проблемы make.
just - это не система сборки как make, это именно исполнитель команд!
Больше никаких Phony Targets и табуляций, привет нормальный синтаксис и передача аргументов!!! 😎
⭐️ Что умеет just:
✅ Автодокументирование команд
Не нужно делать отдельную команду с докой, просто добавь комментарий
Команда с именем
Теперь просто выполняем just и получаем доку из текущего файла.
✅ Удобная работа с переменными окружения
✅ Передача аргументов
команда запуска
✅ Выбор интерпретатора прямо в команде
Пример с инлайн-скриптом на python:
Эта же функция позволит выполнить скрипт как одну команду вместо перезапуска шела для каждой строки
✅ Выполнение команды в определенной директории. Можно указать как релятивный путь так и абсолютный
Также можно задать рабочую директорию глобально
Там еще много интересного:
- поддержка функций
- автокомплиты и интеграции
- экспрешены
- алиасы команд
- группировка команд
- альтернативы команды под разные ОС
- импорт других just-файлов
- цветной вывод
- ... и другие штуковины!
Так что вперёд - ➡️ читать доку!
Репозиторий: ➡️ https://github.com/casey/just
Статья: ➡️ https://www.chicks.net/reference/file_formats/just/
ЗЫ. Кажется, на Makefile я уже не вернусь)
#tools
Но make это не запускалка команд, а система сборки. Мы фактически используем его не по назначению.
И на самом деле альтернатива есть! Некоторое время назад я открыл для себя прекрасный инструмент - just. Он решает все проблемы make.
just - это не система сборки как make, это именно исполнитель команд!
Больше никаких Phony Targets и табуляций, привет нормальный синтаксис и передача аргументов!!! 😎
⭐️ Что умеет just:
✅ Автодокументирование команд
Не нужно делать отдельную команду с докой, просто добавь комментарий
# команда сборки
build:
...
$ just --list
Available recipes:
build # команда сборки
Команда с именем
default запускается по умолчанию если не указано другое, так что я обычно делаю так:default:
just --list
Теперь просто выполняем just и получаем доку из текущего файла.
✅ Удобная работа с переменными окружения
# загрузить из .env
set dotenv-load
# глобальная переменная
export PYTHONPATH := "./src"
# переменная для команды
test $TESTUNG="true":
pytest
✅ Передача аргументов
build target:
@echo 'Build {{target}}...'
команда запуска
$ just build dev
# Build dev...
✅ Выбор интерпретатора прямо в команде
Пример с инлайн-скриптом на python:
system:
#!/usr/bin/env python3
import platform
print(platform.system())
Эта же функция позволит выполнить скрипт как одну команду вместо перезапуска шела для каждой строки
foo:
#!/usr/bin/env sh
for file in ls .; do
echo $file
done
✅ Выполнение команды в определенной директории. Можно указать как релятивный путь так и абсолютный
[working-directory: 'backend']
build:
docker compose build
Также можно задать рабочую директорию глобально
Там еще много интересного:
- поддержка функций
- автокомплиты и интеграции
- экспрешены
- алиасы команд
- группировка команд
- альтернативы команды под разные ОС
- импорт других just-файлов
- цветной вывод
- ... и другие штуковины!
Так что вперёд - ➡️ читать доку!
Репозиторий: ➡️ https://github.com/casey/just
Статья: ➡️ https://www.chicks.net/reference/file_formats/just/
ЗЫ. Кажется, на Makefile я уже не вернусь)
#tools
GitHub
GitHub - casey/just: 🤖 Just a command runner
🤖 Just a command runner. Contribute to casey/just development by creating an account on GitHub.
🔥9❤5
Если запустить REPL с модулем asyncio, то вы входите в особый асинхронный REPL.
В этом режиме
- создаётся и настраивается event loop
- уже импортирован asyncio
- работает await на верхнем уровне
То есть такая команда сработает без ошибок!
Удобно для тестирования асинхронных функций без создания ивентлупов и остальной обвязки.
#tricks #async
user@host:~$ python -m asyncio
asyncio REPL 3.12.7 ...
Use "await" directly instead of "asyncio.run()".
>>> import asyncio
>>>
В этом режиме
- создаётся и настраивается event loop
- уже импортирован asyncio
- работает await на верхнем уровне
То есть такая команда сработает без ошибок!
await asyncio.sleep(3)
Удобно для тестирования асинхронных функций без создания ивентлупов и остальной обвязки.
Работает в: 3.8+
#tricks #async
🔥14😁2👏1
Сгеодня перестал работать Telegram в РФ. Жаль, что вы уже не прочитаете это сообщение. Но если вдруг прочитаете то знайте - канал переехал в MAX!
Подписывайтесь чтобы быть на связи 😎
Подписывайтесь чтобы быть на связи 😎
😁38👏3👎1🔥1🤔1
Стандартная библиотека asyncio это стандарт (начиная с Py3.4) для работы с асинхронным кодом. Но эта библиотека достаточно низкоуровневая, со своими проблемами, устаревшими подходами.
Чтобы исправить это, были созданы разные обертки и альтернативы с реализацией популярных инструментов и паттернов асинхронного программирования. Это такие библиотеки как:
- trio: улучшает корректность выполнения, не оставляя потерянных корутин при ошибках, то есть предлагает Structured Concurrency из коробки.
- curio: упрощение синтаксиса и читаемости кода, больше похоже на работу с потоками.
- anyio: универсальная обертка над asyncio или trio плюс множество вспомогательных инструментов.
В общем, рекомендую почитать про возможности anyio, возможно вы более не будете использовать чистый asyncio в своих проектах)
Это совсем не значит что дефолтный asyncio плох, он тоже даёт достаточный для работы функционал и продолжает развиваться. Например, в версии 3.11 появились TaskGroup, с похожим на trio функционалом. Так что он тоже актуален, просто придется больше написать кода самостоятельно.
#libs #async
Чтобы исправить это, были созданы разные обертки и альтернативы с реализацией популярных инструментов и паттернов асинхронного программирования. Это такие библиотеки как:
- trio: улучшает корректность выполнения, не оставляя потерянных корутин при ошибках, то есть предлагает Structured Concurrency из коробки.
- curio: упрощение синтаксиса и читаемости кода, больше похоже на работу с потоками.
- anyio: универсальная обертка над asyncio или trio плюс множество вспомогательных инструментов.
anyio используется в FastAPI как основная библиотека для работы с асинхронным кодом и вызовом синхронного кода из асинхронного.
В общем, рекомендую почитать про возможности anyio, возможно вы более не будете использовать чистый asyncio в своих проектах)
Это совсем не значит что дефолтный asyncio плох, он тоже даёт достаточный для работы функционал и продолжает развиваться. Например, в версии 3.11 появились TaskGroup, с похожим на trio функционалом. Так что он тоже актуален, просто придется больше написать кода самостоятельно.
#libs #async
❤5👍2
Недавно делал быстрый прототип асинхронного приложения в котором требовалось вызывать много синхронного кода. Да, я знаю, что это не лучший дизайн, но нужно было быстрое решение на один процесс и без очередей. Поэтому я выполнял код в потоках.
Выглядело это примерно так:
В общем работает нормально. Для всех вызовов под капотом используется общий тредпул, всё работает предсказуемо.
Но потребовалось изменить количество запускаемых в пуле потоков (по умолчанию создается 40 воркеров).
Так как дело происходит с FastAPI, делается это через lifespan используя настройки anyio:
Зачем менять количество воркеров?
- уменьшить, если оперативки мало (один тред занимает ~8мб)
- увеличить чтобы выдержать нагрузку
Если есть предложения получше при тех же вводных - предлагайте😉
#async
Выглядело это примерно так:
from fastapi.concurrency import run_in_threadpool
async def execute(data: DataRequest) -> DataResponse:
try:
result = await run_in_threadpool(sync_function, data)
return DataResponse(data=result)
except Exception as e:
return DataResponse(
error=str(e),
success=False,
)
В общем работает нормально. Для всех вызовов под капотом используется общий тредпул, всё работает предсказуемо.
Но потребовалось изменить количество запускаемых в пуле потоков (по умолчанию создается 40 воркеров).
Так как дело происходит с FastAPI, делается это через lifespan используя настройки anyio:
import anyio
@asynccontextmanager
async def lifespan(app: FastAPI):
limiter = anyio.to_thread.current_default_thread_limiter()
limiter.total_tokens = 100
yield
# если вдруг нужно вернуть обратно
limiter.total_tokens = 40
Зачем менять количество воркеров?
- уменьшить, если оперативки мало (один тред занимает ~8мб)
- увеличить чтобы выдержать нагрузку
Если есть предложения получше при тех же вводных - предлагайте😉
#async
❤5👍3🔥1
Nuitka 4.0
Библиотека для компиляции python-кода в исполняемые файлы получила мажорный апдейт.
Ключевые изменения:
- ускорение сборки бинарника в 15 раз
- экспериментальная поддержка компилятора Zig
- возможность выбранные функции оставлять как есть, в виде байт кода через декоратор
- бинарники работают до 30% быстрей (CPU-bound задачи)
- теперь можно вместо отдельного скрипта сборки использовать pyproject.toml. Весь конфиг в одном файле!
- улучшен контроль подключения DLL библиотек для Windows
- улучшена совместимость с рядом популярных и не очень пакетами
И в целом выбран путь на повышение производительности бинарной сборки.
Полная информация ➡️ здесь.
#libs
Библиотека для компиляции python-кода в исполняемые файлы получила мажорный апдейт.
Ключевые изменения:
- ускорение сборки бинарника в 15 раз
- экспериментальная поддержка компилятора Zig
- возможность выбранные функции оставлять как есть, в виде байт кода через декоратор
@nuitka_ignore- бинарники работают до 30% быстрей (CPU-bound задачи)
- теперь можно вместо отдельного скрипта сборки использовать pyproject.toml. Весь конфиг в одном файле!
- улучшен контроль подключения DLL библиотек для Windows
- улучшена совместимость с рядом популярных и не очень пакетами
И в целом выбран путь на повышение производительности бинарной сборки.
Полная информация ➡️ здесь.
#libs
❤9👍2👏1😱1
В асинхронных приложениях есть один не всегда очевидный момент, который приводит к неявным багам - это общие глобальные объекты. Да, это в целом антипаттерн, но иногда такие объекты действительно нужны и вполне уместны. Например, когда вы завязаны на уже существующем коде и не можете его поменять, но переменную подставлять надо, при этом явно пробросить её не получится. Для этого используется
Случаи бывают разные но я приведу самый понятный пример - логирование.
Допустим, мы не можем передать id юзера куда-то внутрь фреймворка, но можем использовать его в своем хендлере подставляя как переменную. В примере будет без хендлера но суть та же.
Во всех выводах id должен совпадать.
- Точно так же можно подставлять атрибуты у инстансов синглтонов.
- Контекст наследуется дочерними корутинами.
- Не стоит увлекаться этим способом, он прилично усложняет логику. Явное лучше неявного.
@asyncio @tricks
ContexctVar.Случаи бывают разные но я приведу самый понятный пример - логирование.
Допустим, мы не можем передать id юзера куда-то внутрь фреймворка, но можем использовать его в своем хендлере подставляя как переменную. В примере будет без хендлера но суть та же.
import asyncio
from contextvars import ContextVar
import random
# это переменная, которая будет разной для каждой корутины
user_id_ctx = ContextVar("user_id", default=-1)
async def handle_request(user_name, user_id):
# устанавливаем значение для текущей корутины и её дочерних корутин
user_id_ctx.set(user_id)
print(f"Create {user_name} == {user_id}")
await asyncio.sleep(random.random())
# id не передаётся в вызов
await process_order(user_name)
async def process_order(user_name):
# получаем значение из локального контекста
current_user_id = user_id_ctx.get()
print(f"Log {user_name}: {current_user_id}")
async def main():
await asyncio.gather(
*[handle_request(f"user {i}", i) for i in range(10)],
)
if __name__ == "__main__":
asyncio.run(main())
Во всех выводах id должен совпадать.
- Точно так же можно подставлять атрибуты у инстансов синглтонов.
- Контекст наследуется дочерними корутинами.
- Не стоит увлекаться этим способом, он прилично усложняет логику. Явное лучше неявного.
@asyncio @tricks
👍5❤2