В Python 3.14 появится реализация PEP 750 и новый способ форматирования: t-strings. Это так называемые Template Strings.
Синтаксис такой же как с f-strings, но форматирование происходит не сразу.
Вместо строки создаётся объект Template, который внутри себя содержит исходную информацию, сырую строку (
Это позволяет произвести дополнительную обработку данных перед форматированием, например для усиления безопасности.
В примерах можно увидеть как строка с HTML кодом дополнтиельно обрабатывается чтобы избежать инъекции JS кода за счет экранирования служебных символов.
Конечно, этим примером возможности не ограничивюатся. Более подробно про функционал будет понятно ближе к релизу в конце года. Сейчас доступно в сборках 3.14.0a7+ из этой ветки.
Простой пример создания шаблона
Что является шорткатом для
В обоих случаях объект получим идентичный
Больше примеров ➡️ здесь
#pep
Синтаксис такой же как с 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
Python Enhancement Proposals (PEPs)
PEP 750 – Template Strings | peps.python.org
This PEP introduces template strings for custom string processing.
👍8🤔4👎2🔥1😢1
Недавно возникла такая задача: требовалось из Python скрипта запустить дочерний процесс, тоже Python скрипт, и получить от него некоторые данные. В моём случае это был некий словарь который мог быть сериализован в JSON формат, но это не так важно.
Какие есть варианты это сделать?
1️⃣ Передать дочернему процессу путь к файлу куда и будет записан результат.
После завершение дочернего процесса просто читаем данные из файла.
✅ легко и понятно, все так умеют делать
✅ можно перемещаться по файлу через seek
✅ можно прочитать когда-нибудь потом
❌ обращение к файловой системе, бывает относительно не быстро
❌ какое-то время файл будет доступен любому процессу, небезопасно
❌ только полная запись данных перед чтением (на самом деле есть вариант чтения во время записи, но это не то что мы хотим делать😖)
2️⃣ TCP/UDP сокет
✅ универсально, даже для неродственных процессов
✅ нет обращения в файловой системе (Unix-сокеты это почти файлы но всё равно не совсем)
✅ можно стримить данные
❌ нужна какая-то система авторизация чтобы обезопасить доступ
❌ оверхед для простой передачи данных, особенно если процесс дочерний. Требуется поднятие сервера и организция клиента со всеми вытекающими зависимостями и конструкциями
3️⃣ Парсить аутпут дочернего процесса.
✅ быстро, так как пайпы работают через оперативную память
✅ нет обращения к файловой системе и всех действий с этим связанных
✅ пайп привязан к файловым дескрипторам конкретных процессов, и доступ к нему могут получить только те процессы, которые унаследовали этот дескриптор (или получили другим способом)
✅ передача данных в режиме стрима
❌ неудобно если дочерний процесс пишет логи в stdout, нужна какая-то логика выделения только нужного или как-то отключать логи в надежде что никто другой туда ничего не напишет.
❌ нельзя перемещаться через seek
Если у вас взаимодействие с дочерним процессом, то есть самый простой вариант - кастомный пайп!✨
Это как
Для простоты примера сделаем один пайп. Дочерний процесс должен что-то прислать в родительский процесс.
👮♂️РОДИТЕЛЬСКИЙ ПРОЦЕСС
1. Создаем новый пайп
2. Запускаем дочерний процесс передавая ему номер файла
3. Читаем данные
Чтение прекратится когда файл закроется, за это отвечает контекстный менеджер
Стандартные пайпы тоже можно прочитать
👶 Переходим к коду дочернего процесса.
1. Получаем номер дескриптора
Пишем в него данные
Вот и всё, мы сделали коммуникацию между двумя процессами через кастомный пайп ⭐️
Быстро, легко, безопасно!
С помощью двух пайпов можно ораганизовать передачу сообщений между процессами в обе стороны.
Пример с JSON можно глянуть здесь↗️
#tricks
Какие есть варианты это сделать?
1️⃣ Передать дочернему процессу путь к файлу куда и будет записан результат.
После завершение дочернего процесса просто читаем данные из файла.
✅ легко и понятно, все так умеют делать
✅ можно перемещаться по файлу через seek
✅ можно прочитать когда-нибудь потом
❌ обращение к файловой системе, бывает относительно не быстро
❌ какое-то время файл будет доступен любому процессу, небезопасно
❌ только полная запись данных перед чтением (на самом деле есть вариант чтения во время записи, но это не то что мы хотим делать😖)
2️⃣ TCP/UDP сокет
✅ универсально, даже для неродственных процессов
✅ нет обращения в файловой системе (Unix-сокеты это почти файлы но всё равно не совсем)
✅ можно стримить данные
❌ нужна какая-то система авторизация чтобы обезопасить доступ
❌ оверхед для простой передачи данных, особенно если процесс дочерний. Требуется поднятие сервера и организция клиента со всеми вытекающими зависимостями и конструкциями
3️⃣ Парсить аутпут дочернего процесса.
✅ быстро, так как пайпы работают через оперативную память
✅ нет обращения к файловой системе и всех действий с этим связанных
✅ пайп привязан к файловым дескрипторам конкретных процессов, и доступ к нему могут получить только те процессы, которые унаследовали этот дескриптор (или получили другим способом)
✅ передача данных в режиме стрима
❌ неудобно если дочерний процесс пишет логи в stdout, нужна какая-то логика выделения только нужного или как-то отключать логи в надежде что никто другой туда ничего не напишет.
❌ нельзя перемещаться через seek
Если у вас взаимодействие с дочерним процессом, то есть самый простой вариант - кастомный пайп!✨
Это как
stdout или stderr, но только еще один канал в котором не будет никаких логов и сообщений об ошибках.Для простоты примера сделаем один пайп. Дочерний процесс должен что-то прислать в родительский процесс.
👮♂️РОДИТЕЛЬСКИЙ ПРОЦЕСС
1. Создаем новый пайп
import os. subprocess
read_fd, write_fd = os.pipe()
# важный момент! добавляем возможность наследовать дескриптор дочерним процессом. Обязательно после Python 3.4+ (PEP 446)
os.set_inheritable(write_fd, True)
2. Запускаем дочерний процесс передавая ему номер файла
process = subprocess.Popen(
[sys.executable, child_script, str(write_fd)],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
close_fds=False # важный момент! это нужно, чтобы дочерний процесс сохранил все открытые дескрипторы, а не только стандартные потоки
)
os.close(write_fd) # закрываем дескриптор чтобы у родителя не висел открытый конец записи, иначе в читающем конце не наступит EOF
3. Читаем данные
with os.fdopen(read_fd, 'r') as data_pipe:
data = data_pipe.read()
print('RECEIVED:', data)
Чтение прекратится когда файл закроется, за это отвечает контекстный менеджер
with в дочернем процессе.Стандартные пайпы тоже можно прочитать
stdout_log, stderr_log = process.communicate()
print(stdout_log)
print(stderr_log)
👶 Переходим к коду дочернего процесса.
1. Получаем номер дескриптора
write_pipe_fd = int(sys.argv[-1])
Пишем в него данные
with os.fdopen(write_pipe_fd, 'w') as data_pipe:
data_pipe.write('Hello!')
data_pipe.flush()
Вот и всё, мы сделали коммуникацию между двумя процессами через кастомный пайп ⭐️
Быстро, легко, безопасно!
С помощью двух пайпов можно ораганизовать передачу сообщений между процессами в обе стороны.
Пример с JSON можно глянуть здесь↗️
#tricks
Gist
custom-pipe-example.py
GitHub Gist: instantly share code, notes, and snippets.
🔥11👍4❤2
Быстрый встроенный профайлинг на Linux с помощью time
Покажет время выполнения процесса
Но это встроенная команда из моей оболочки. Есть такая же GNU-утилита и она может показывать больше информации. Но нужно вызывать по абсолютному пути, так как builtin команда имеет бОльший приоритет.
Кроме времени исполнения будет также показано много другой полезной информации
- эффективность использования CPU (в %)
- максимальный объем занятой памяти
- обращения к файлам
- код выхода
И другие сведения.
#tricks
time python -c 'for i in range(10**7): i**2'
Покажет время выполнения процесса
real 0m2,470s
user 0m2,405s
sys 0m0,074s
real - Общее время, прошедшее с момента запуска до завершения программы. Включая время ожидания I\O или переключения контекста.user - Количество времени, которое CPU потратил на выполнение кода самой программы в пользовательском режиме.sys - Количество времени, которое CPU потратил на выполнение системных вызовов (операций ядра, таких как чтение/запись файлов, управление памятью) от имени программы.Но это встроенная команда из моей оболочки. Есть такая же GNU-утилита и она может показывать больше информации. Но нужно вызывать по абсолютному пути, так как builtin команда имеет бОльший приоритет.
/usr/bin/time -v python -c 'for i in range(10**7): i**2'
Command being timed: "python -c for i in range(10**7): i**2"
User time (seconds): 2.38
System time (seconds): 0.07
Percent of CPU this job got: 100%
...
Кроме времени исполнения будет также показано много другой полезной информации
- эффективность использования CPU (в %)
- максимальный объем занятой памяти
- обращения к файлам
- код выхода
И другие сведения.
#tricks
🔥7❤2👍2
7.09.2025 состоялся релиз Pithon 3.14!
На фоне хайпа про NoGIL всё позабыли про другие фичи. Особенно про Multiple Interpreters, который обещает изоляцию процессов но с эффективностью потоков! На сколько действительно это будет эффективно мы узнаем позже, потому что сейчас это лишь первый релиз с ограничениями и недоработками.
Но что там про NoGIL? Теперь этот режим не экспериментальный, а официально поддерживаемый, но опциональный.
Чтобы запустить без GIL нужна специальная сборка. И перед стартом нужно объявить переменную
Для вас я собрал готовый репозиторий где достаточно запустить скрпит, который всё сделает:
▫️ соберет релизный Python 3.14 в новый Docker-образ
▫️ запустит тесты в контейнере (GIL, NoGIL, MultiInterpreter)
▫️ распечатает результаты
Тест очень простой, усложняйте сами)
Вот какие результаты у меня:
Если сравнивать GIL и NoGIL, то на мои 32 ядра прирост х7-x10 (почему не х32? 🤷). При этом нам обещают что скорости будут расти с новыми релизами.
Режим без GIL похож (визуально) на async, тоже параллельно, тоже не по порядку. Но это не IO! и от того некоторый диссонанс в голове 😵💫, нас учили не так!
Интересно, что чистый
Ну и где-то плачет один адепт мульти-интерпретаторов😭 Теперь нужно искать где они могут пригодиться с такой-то скоростью. Скорее всего своя область применения найдется.
Отдельно я затестил память и вот что вышло на 32 потока:
Пока не знаю как к этому относиться)
В целом - радует направление развития!
#release
На фоне хайпа про NoGIL всё позабыли про другие фичи. Особенно про Multiple Interpreters, который обещает изоляцию процессов но с эффективностью потоков! На сколько действительно это будет эффективно мы узнаем позже, потому что сейчас это лишь первый релиз с ограничениями и недоработками.
Но что там про NoGIL? Теперь этот режим не экспериментальный, а официально поддерживаемый, но опциональный.
Чтобы запустить без GIL нужна специальная сборка. И перед стартом нужно объявить переменную
PYTHON_GIL=0Для вас я собрал готовый репозиторий где достаточно запустить скрпит, который всё сделает:
▫️ соберет релизный Python 3.14 в новый Docker-образ
▫️ запустит тесты в контейнере (GIL, NoGIL, MultiInterpreter)
▫️ распечатает результаты
Тест очень простой, усложняйте сами)
Вот какие результаты у меня:
=== Running ThreadPoolExecutor GIL ON
TOTAL TIME: 45.48 seconds
=== Running ThreadPoolExecutor GIL OFF
TOTAL TIME: 6.14 seconds
=== Running basic Thread GIL ON
TOTAL TIME: 45.54 seconds
=== Running basic Thread GIL OFF
TOTAL TIME: 4.74 seconds
=== Running with Multi Interpreter
TOTAL TIME: 18.30 seconds
Если сравнивать GIL и NoGIL, то на мои 32 ядра прирост х7-x10 (почему не х32? 🤷). При этом нам обещают что скорости будут расти с новыми релизами.
Режим без GIL похож (визуально) на async, тоже параллельно, тоже не по порядку. Но это не IO! и от того некоторый диссонанс в голове 😵💫, нас учили не так!
Интересно, что чистый
Thread работает быстрей чем ThreadPoolExecutor без GIL.Ну и где-то плачет один адепт мульти-интерпретаторов😭 Теперь нужно искать где они могут пригодиться с такой-то скоростью. Скорее всего своя область применения найдется.
Отдельно я затестил память и вот что вышло на 32 потока:
ThreadPoolExecutor GIL ON
305.228 MB
ThreadPoolExecutor GIL OFF
500.176 MB
basic Thread GIL ON
90.668 MB
basic Thread GIL OFF
472.444 MB
with Multi Interpreter
1267.788 MB
Пока не знаю как к этому относиться)
В целом - радует направление развития!
#release
Python documentation
What’s new in Python 3.14
Editors, Adam Turner and Hugo van Kemenade,. This article explains the new features in Python 3.14, compared to 3.13. Python 3.14 was released on 7 October 2025. For full details, see the changelog...
❤11👍3🔥2👎1
Использование Pydantic сегодня стало нормой, и это правильно. Но иногда на ревью вижу, что используют его не всегда корректно.
Например, метод
В данном случае класс
Специально для тех, кто всё еще так делает - в этом нет необходимости!
Pydantic может это сделать сам, просто нужно добавить параметр
#pydantic #libs
Например, метод
BaseModel.model_dump() по умолчанию не преобразует стандартные типы, такие как datetime, UUID или Decimal, в простой сериализуемый для JSON вид. Тогда пишут кастмоный сериализатор для этих типов чтобы функция json.dump() не падала с ошибкой.import uuid
from datetime import datetime
from decimal import Decimal
from uuid import UUID
from pydantic import BaseModel
class MyModel(BaseModel):
id: UUID
date: datetime
value: Decimal
obj = MyModel(
id=uuid.uuid4(),
date=datetime.now(),
value='1.23'
)
print(obj.model_dump())
# не подходит для json.dump
# {
# 'id': UUID('4f8c1bc4-25fd-40cd-9dbe-2c73639b0dc1'),
# 'date': datetime.datetime(2025, 12, 12, 12, 12, 12, 111111),
# 'value': Decimal('1.23')
# }
# добавляем свой кастомный сериализатор
json.dumps(obj.model_dump(), cls=MySerializer)
# {
# 'id': '4f8c1bc4-25fd-40cd-9dbe-2c73639b0dc1',
# 'date': '2025-12-12T12:12:12.111111',
# 'value': '1.23'
# }
В данном случае класс
MySerializer обрабатывает datetime, UUID и Decimal. Например так:class MySerializer(json.JSONEncoder):
def default(self, o):
if isinstance(o, Decimal):
return str(o)
elif isinstance(o, datetime):
return o.isoformat()
elif isinstance(o, UUID):
return str(o)
return super().default(o)
Специально для тех, кто всё еще так делает - в этом нет необходимости!
Pydantic может это сделать сам, просто нужно добавить параметр
mode="json".json.dumps(obj.model_dump(mode="json"))
# {
# 'id': '4f8c1bc4-25fd-40cd-9dbe-2c73639b0dc1',
# 'date': '2012-12-12T12:12:12.111111',
# 'value': '1.23'
# }
#pydantic #libs
❤8👍6🔥4
⚠️После небольшого перегрева на работе я взял паузу на месяц и занялся своими проектами.
Рекомендую! Полезно иногда остановиться, и оглядеться вокруг, восстановить силы и сделать ранее себе (и другим) обещанное.
В общем, теперь я снова готов активно кодить! Если есть что предложить - смело пишите в личку!
📝 https://paulwinex.com/resume/
#offtop
Рекомендую! Полезно иногда остановиться, и оглядеться вокруг, восстановить силы и сделать ранее себе (и другим) обещанное.
В общем, теперь я снова готов активно кодить! Если есть что предложить - смело пишите в личку!
📝 https://paulwinex.com/resume/
#offtop
❤4👏1