Библиотека Python разработчика | Книги по питону
Погружение в CPython и архитектуру. Разбираем неочевидное поведение (GIL, Memory), Best Practices (SOLID, DDD) и тонкости Django/FastAPI. Решаем задачи с подвохом и оптимизируем алгоритмы. 🐍 По всем вопросам @evgenycarter РКН clck.ru/3Ko7Hq
Ko'proq ko'rsatish📈 Telegram kanali Библиотека Python разработчика | Книги по питону analitikasi
Библиотека Python разработчика | Книги по питону (@bookpython) Rus til segmentidagi kanali faol ishtirokchi. Hozirda hamjamiyat 17 973 obunachidan iborat bo'lib, Texnologiyalar & Aralashmalar toifasida 7 274-o'rinni va Rossiya mintaqasida 36 654-o'rinni egallagan.
📊 Auditoriya ko‘rsatkichlari va dinamika
невідомо sanasidan buyon loyiha tez o‘sib, 17 973 obunachiga ega bo‘ldi.
28 Oktabr, 2026 dagi oxirgi ma’lumotlarga ko‘ra kanal barqaror faollikka ega. Oxirgi 30 kunda obunachilar soni -96 ga, so‘nggi 24 soatda esa -2 ga o‘zgardi va umumiy qamrov yuqori darajada qolmoqda.
- Tasdiqlash holati: Tasdiqlanmagan
- Jalb etish (ER): Auditoriya o‘rtacha 5.41% darajada jalb etiladi. Nashrdan keyingi dastlabki 24 soatda kontent odatda umumiy obunachilar sonining 2.64% ini tashkil etuvchi reaksiyalarni to‘playdi.
- Post qamrovi: Har bir post o‘rtacha 973 marta ko‘riladi; birinchi sutkada odatda 475 ta ko‘rish yig‘iladi.
- Reaksiyalar va o‘zaro ta’sir: Auditoriya faol: har bir postga o‘rtacha 4 ta reaksiya keladi.
- Tematik yo‘nalishlar: Kontent numbers, yield, модуль, none, декоратор kabi asosiy mavzularga jamlangan.
📝 Tavsif va kontent siyosati
Muallif resursni shaxsiy fikrni ifoda etish maydoni sifatida ta’riflaydi:
“Погружение в CPython и архитектуру. Разбираем неочевидное поведение (GIL, Memory), Best Practices (SOLID, DDD) и тонкости Django/FastAPI. Решаем задачи с подвохом и оптимизируем алгоритмы. 🐍
По всем вопросам @evgenycarter
РКН clck.ru/3Ko7Hq”
Yuqori yangilanish chastotasi (oxirgi ma’lumot 29 Oktabr, 2026 da olingan) sababli kanal doimo dolzarb va katta qamrovli bo‘lib qoladi. Analitika auditoriya kontent bilan faol hamkorlik qilishini, uni Texnologiyalar & Aralashmalar toifasidagi muhim ta’sir nuqtasiga aylantirishini ko‘rsatadi.
py-spy.
🔍 Что такое py-spy?
py-spy это sampling-профайлер для Python, который не требует модификации кода и может подключаться к уже работающим процессам. Он написан на Rust, работает очень быстро и почти не влияет на производительность.
🛠 Установка:
pip install py-spy
Или, если хочется поставить бинарник напрямую:
curl -sSL https://install.python-poetry.org | python3 -
🚀 Примеры использования:
1. Снять снимок с работающего процесса:
py-spy top --pid 12345
Альтернатива htop, но показывает, какие функции Python жрут CPU.
2. Записать flamegraph:
py-spy record -o profile.svg --pid 12345
Откроется красивая SVG-шечка, где видно, куда утекает время выполнения.
3. Запустить скрипт с профилированием:
py-spy top -- python my_script.py
🧠 Зачем это нужно?
- Падает производительность? Посмотри, какие функции грузят процессор.
- Программа зависла? Снимок покажет, где именно.
- Хотите оптимизировать горячие участки? Flamegraph быстро выведет подозреваемых.
🔥 Совет от меня: py-spy умеет работать с контейнерами и виртуальными окружениями, просто указывайте --pid правильного процесса. Идеален для DevOps'а и продакшн-серверов.
📲 Мы в MAX
👉@BookPythonpdb.
🔍 Быстрая отладка с pdb
Часто, когда код не работает как надо, мы начинаем закидывать print()-ами. Но это неудобно, медленно и мусорит код. Вместо этого вставь в нужное место строчку:
import pdb; pdb.set_trace()
Когда выполнение дойдет до этой строки, ты попадешь в интерактивную консоль отладчика прямо в терминале. Дальше можно:
- n (next) — перейти к следующей строке;
- s (step) — зайти внутрь функции;
- c (continue) — продолжить выполнение;
- l (list) — показать текущий контекст;
- p var — вывести значение переменной var.
💡 Пример
def calc(a, b):
import pdb; pdb.set_trace()
result = a + b
return result
calc(2, 3)
На строке с pdb.set_trace() ты остановишься и сможешь изучить, что происходит внутри.
Зачем это нужно?
- Понять, почему что-то идет не так.
- Посмотреть, какие значения у переменных прямо в момент ошибки.
- Быстро отладить без запуска IDE - удобно в Docker, SSH или при работе с cron.
Попробуй - один раз освоишь, и уже не захочешь возвращаться к print().
📲 Мы в MAX
👉@BookPython
a = b = c = 42
Выглядит как цепочка присваиваний в C, но работает совершенно иначе. В C результат одного присваивания используется в следующем:
a = (b = (c = 42))
В Python всё не так. Операция присваивания не возвращает результат — это оператор, а не выражение. Вместо этого происходит несколько присваиваний слева направо:
2 0 LOAD_CONST 1 (42)
2 DUP_TOP
4 STORE_FAST 0 (a)
6 DUP_TOP
8 STORE_FAST 1 (b)
10 STORE_FAST 2 (c)
📲 Мы в MAX
👉@BookPython__hash__, который возвращает целое число. Для получения хеша значения используется встроенная функция hash.
Встроенные типы, которые являются неизменяемыми, по умолчанию хешируемы. Все пользовательские объекты тоже хешируемы, но есть нюанс. Если вы определяете метод __eq__ для своего типа, то вы также должны определить __hash__ таким образом, чтобы hash(a) == hash(b) для всех a и b, которые считаются равными. Нарушение этого правила может привести к некорректной работе словаря:
class A:
def __init__(self, x):
self.x = x
def __hash__(self):
return random.randrange(10000)
def __eq__(self, other):
return self.x == other.x
d = {}
d[A(2)] = 2
d.get(A(2), 0)
# Вывод: 0
Обратите внимание: как только вы определяете __eq__ в классе, реализация __hash__ по умолчанию удаляется, так как она больше не подходит (по умолчанию все значения считаются неравными).
📲 Мы в MAX
👉@BookPythonlst = [1, 2, 3, 4, 5]
lst = []
Этот способ создаёт новый пустой список, но старая ссылка остаётся в памяти, если на неё есть другие ссылки.
2️⃣ Использование .clear()
lst = [1, 2, 3, 4, 5]
lst.clear()
Метод .clear() очищает список на месте, не создавая новый объект. Это предпочтительный способ, если список используется в нескольких местах.
3️⃣ Использование del
lst = [1, 2, 3, 4, 5]
del lst[:]
Работает аналогично .clear(), но выглядит чуть менее очевидно.
4️⃣ Удаление списка полностью
lst = [1, 2, 3, 4, 5]
del lst
Этот вариант полностью удаляет переменную lst. Если потом попробовать к ней обратиться, будет ошибка NameError.
🔹 Какой способ лучше?
• Если нужно просто очистить список, используйте .clear().
• Если хотите заменить его новым объектом - lst = [].
• del lst[:] – редкий вариант, но возможен.
• del lst подходит, если список больше не нужен в программе.
Какой вариант используете вы? Пишите в комментариях!
📲 Мы в MAX
👉@BookPythonelse в for и while
Многие не знают, что в Python циклы for и while могут иметь блок else. Он выполняется, если цикл не был прерван через break.
✅ Пример:
numbers = [1, 3, 5, 7]
for num in numbers:
if num % 2 == 0:
print("Есть чётное число!")
break
else:
print("Чётных чисел нет.")
🔹 Если в списке нет чётных чисел, сработает else.
2. "Распаковка" переменных
В Python можно присваивать сразу несколько значений одной строкой.
✅ Пример:
a, b, c = 1, 2, 3
print(a, b, c) # 1 2 3
Можно менять местами значения без временной переменной:
x, y = 5, 10
x, y = y, x
print(x, y) # 10 5
3. Используем _ в больших числах
Чтобы числа легче читались, можно разделять разряды _.
✅ Пример:
big_number = 1_000_000_000
print(big_number) # 1000000000
Это просто синтаксический сахар, Python игнорирует _ при вычислениях.
4. Получаем значение из словаря с запасным вариантом
Вместо if key in dict можно использовать .get(), чтобы избежать KeyError.
✅ Пример:
user_data = {"name": "Alice"}
age = user_data.get("age", 18) # Если ключа "age" нет, вернётся 18
print(age) # 18
5. "Распаковка" списка в аргументы функции
Оператор * позволяет передавать элементы списка в функцию как отдельные аргументы.
✅ Пример:
def greet(name, age):
print(f"Привет, {name}! Тебе {age} лет.")
user_info = ["Иван", 25]
greet(*user_info) # Привет, Иван! Тебе 25 лет.
То же работает со словарями через **:
user_dict = {"name": "Ольга", "age": 30}
greet(**user_dict)
Эти фишки делают код лаконичнее и понятнее.
📲 Мы в MAX
👉@BookPythonTelegram всё чаще используется не только как мессенджер, но и как удобный интерфейс для сервисов и внутренних инструментов.На вебинаре разберем: ✔️ Базовую архитектуру взаимодействия Django и Telegram-бота ✔️ Основные способы обмена данными между веб-приложением и мессенджером ✔️Практические сценарии использования Telegram как интерфейса для Django-проекта В результате вебинара вы: - Поймёте, как связать Django и Telegram-бота на базовом уровне - Узнаете, в каких задачах Telegram может быть полезным интерфейсом - Получите основу, которую сможете развить и применить в собственных проектах 🔗 Ссылка на регистрацию: https://vk.cc/cU2PJU Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
import numpy as np
import time
def sum_of_squares(n):
result = 0
for i in range(n):
result += i ** 2
return result
n = 10**7
start = time.time()
sum_of_squares(n)
print("Обычный Python:", time.time() - start)
Теперь ускорим её с помощью Numba:
from numba import jit
@jit(nopython=True)
def sum_of_squares_numba(n):
result = 0
for i in range(n):
result += i ** 2
return result
start = time.time()
sum_of_squares_numba(n)
print("С Numba:", time.time() - start)
📊 Результат:
✅ Код на чистом Python выполняется ~5-10 раз медленнее, чем с Numba.
✅ Numba особенно полезна для математических вычислений и обработки массивов.
✅ Простая аннотация @jit(nopython=True) уже даёт мощный прирост скорости!
Где применять?
✔ Численные расчёты
✔ Обработку данных
✔ Алгоритмы машинного обучения
Попробуйте Numba и напишите в комментариях, удалось ли вам ускорить свой код!
📲 Мы в MAX
👉@BookPythonpip install rich
2️⃣ Typer – современный способ писать CLI-приложения. Работает на основе аннотаций типов и делает разработку CLI удобнее.
📌 pip install typer
3️⃣ Pendulum – альтернатива datetime, но с удобным API и встроенной поддержкой часовых поясов.
📌 pip install pendulum
4️⃣ HTTPX – асинхронный клиент для работы с HTTP-запросами. Поддерживает async/await, в отличие от requests.
📌 pip install httpx
5️⃣ Pydantic – мощный инструмент для валидации данных и работы с моделями. Особенно полезен в FastAPI.
📌 pip install pydantic
6️⃣ Poetry – современный менеджер зависимостей. Упрощает работу с виртуальными окружениями и пакетами.
📌 pip install poetry
7️⃣ Loguru – удобная альтернатива стандартному logging. Позволяет логировать без лишнего кода.
📌 pip install loguru
8️⃣ FastAPI – один из самых быстрых Python-фреймворков для создания API. Использует аннотации типов и async/await.
📌 pip install fastapi
9️⃣ Tqdm – библиотека для удобных progress-bar'ов в терминале. Незаменима при обработке больших данных.
📌 pip install tqdm
🔟 Black – автоматический форматтер кода, который придерживается строгого стиля. Просто устанавливаешь – и больше не думаешь о стиле кода.
📌 pip install black
📲 Мы в MAX
👉@BookPythonmultiprocessing.Pool - это то, что вам нужно. Он создает несколько процессов и автоматически распределяет между ними задачи. Просто создайте пул с Pool(number_of_processes) и выполните p.map с списком входных данных.
import math
from multiprocessing import Pool
inputs = [i ** 2 for i in range(100, 130)]
def f(x):
return len(str(math.factorial(x)))
# Однопоточное выполнение
%timeit [f(x) for x in inputs]
# 1.44 s ± 19.2 ms per loop (...)
# Параллельное выполнение с 4 процессами
p = Pool(4)
%timeit p.map(f, inputs)
# 451 ms ± 34 ms per loop (...)
Также можно не указывать параметр number_of_processes, по умолчанию он равен количеству ядер CPU в системе.
📲 Мы в MAX
👉@BookPythonabc.ABC в Python мы привыкли к Nominal Subtyping (Именная подтипизация). Чтобы объект считался Bird, он должен явно наследоваться от Bird.
Это создает жесткую связность (coupling): ваша реализация должна знать об интерфейсе и импортировать его.
С приходом typing.Protocol (Python 3.8+) мы получили Structural Subtyping (Структурная подтипизация).
В чем суть?
Если класс имеет метод quack(), то это Утка. Неважно, от чего он наследуется. Это и есть та самая «утиная типизация», но теперь поддерживаемая статическим анализатором (mypy, pyright, IDE).
Сравним код:
❌ Старый путь (ABC):
from abc import ABC, abstractmethod
# 1. Жестко определяем интерфейс
class SenderABC(ABC):
@abstractmethod
def send(self, msg: str) -> None: pass
# 2. Обязаны наследоваться!
class EmailService(SenderABC):
def send(self, msg: str) -> None:
print(f"Email: {msg}")
def alert(sender: SenderABC):
sender.send("Alert!")
✅ Новый путь (Protocol):
from typing import Protocol
# 1. Описываем, "что мы ждем от объекта"
class SenderProto(Protocol):
def send(self, msg: str) -> None: ...
# 2. Реализация НИЧЕГО не знает про Protocol
# Никаких импортов и наследования!
class SmsService:
def send(self, msg: str) -> None:
print(f"SMS: {msg}")
# Mypy счастлив: SmsService имеет нужную структуру (метод send)
def alert(sender: SenderProto):
sender.send("Alert!")
alert(SmsService())
Киллер-фича: Retroactive Abstraction (Ретроактивная абстракция)
Представьте, что вы используете стороннюю библиотеку (например, boto3 или клиент Redis). Вы не можете заставить их классы наследоваться от ваших ABC.
С помощью Protocol вы можете создать интерфейс для уже существующего чужого кода, не меняя его, и типизировать свои функции.
Нюансы для Middle+:
1. Runtime: По умолчанию isinstance(obj, MyProtocol) выбросит ошибку. Протоколы - это compile-time фича. Если нужна проверка в рантайме, декорируйте протокол @runtime_checkable.
2. Свойства: В протоколе можно описывать не только методы, но и поля через @property или просто аннотации типов.
Используйте Протоколы, чтобы развязать зависимости между модулями. Это основа принципа Dependency Inversion в Python.
#python #typing #mypy #architecture #clean_code
📲 Мы в MAX
👉@BookPythonХорошее API — это не только код, но и понятная документация. Без неё REST-сервис быстро превращается в чёрный ящик для команды и клиентов.Что будет на вебинаре: ✔️ Интеграция библиотеки drf-spectacular для генерации схемы OpenAPI 3.0. ✔️ Кастомизация документации: использование декоратора
@extend_schema и типизации.
✔️ Подключение и настройка интерфейсов Swagger UI и Redoc.
В результате вебинара вы получите:
- Навык быстрой настройки автодокументации в существующих проектах.
- Умение описывать сложные параметры запросов и ответов.
- Готовый интерактивный интерфейс для тестирования API внутри браузера.
🔗 Ссылка на регистрацию: https://vk.cc/cTPi2Z
Реклама. ООО «Отус онлайн-образование», ОГРН 11777466185761, 2, 3. Пока что все понятно. А как насчет кортежа, содержащего только один элемент? Вы просто добавляете завершающую запятую к единственному значению: 1,. Это выглядит несколько некрасиво и может быть подвержено ошибкам, но логика понятна.
А как насчет пустого кортежа? Это просто запятая? Нет, это (). Значит ли это, что круглые скобки создают кортеж так же, как и запятые? Нет, это не так. (4) — это не кортеж, это просто 4.
Пример:
a = [
(1, 2, 3),
(1, 2),
(1),
(),
]
[type(x) for x in a]
# Результат: [tuple, tuple, int, tuple]
Чтобы все стало еще более запутанным, литералы кортежей часто требуют дополнительных круглых скобок. Если вы хотите, чтобы кортеж был единственным аргументом функции, то f(1, 2, 3) не сработает по очевидной причине — вместо этого нужно написать f((1, 2, 3)).
📲 Мы в MAX
👉@BookPythonyield и оптимизация скоупов
Если вы все еще пишете def teardown_method(self): в классах тестов, вы не используете мощь Pytest на 100%.
Фикстуры (fixtures) - это не просто способ передать данные. Это полноценный механизм управления жизненным циклом зависимостей (DI).
1. yield вместо return: Встроенный Teardown
В Pytest фикстура может "замереть", отдать управление тесту, а потом продолжить выполнение. Это реализуется через генератор yield.
Код до yield - это setUp.
Код после yield - это tearDown.
Пример (временная база данных):
import pytest
from sqlalchemy import create_engine
@pytest.fixture
def db_engine():
# Setup: Поднимаем соединение
engine = create_engine("sqlite:///:memory:")
# Передаем объект в тест
yield engine
# Teardown: Этот код выполнится ПОСЛЕ завершения теста
# (даже если тест упал с ошибкой!)
engine.dispose()
Это гарантирует, что ресурсы будут освобождены, и вам не нужны try/finally блоки внутри самих тестов.
2. Scopes: Не создавайте мир заново
По умолчанию фикстура имеет scope='function'. Она создается и умирает для каждого теста. Это безопасно, но медленно, если мы говорим о поднятии Docker-контейнера или коннекта к БД.
Используйте scope='session' для тяжелых ресурсов, которые можно переиспользовать.
Паттерн "Изоляция при общем ресурсе":
Частая задача Middle+: иметь одну БД на весь прогон тестов (быстро), но чистые таблицы для каждого теста (изолированно).
Решение: комбинируем скоупы.
# Живет весь прогон тестов (создается 1 раз)
@pytest.fixture(scope="session")
def db_engine():
engine = create_engine(...)
yield engine
engine.dispose()
# Живет 1 тест (создается N раз)
@pytest.fixture(scope="function")
def db_session(db_engine):
# Берем engine из сессионной фикстуры
connection = db_engine.connect()
transaction = connection.begin() # Начали транзакцию
session = Session(bind=connection)
yield session
session.close()
# ROLLBACK транзакции после теста вернет базу в исходное состояние!
transaction.rollback()
connection.close()
Итог:
🟢Используйте yield для очистки ресурсов.
🟢Тяжелые объекты (Engine, Client, Container) - в scope='session'.
🟢Легкие объекты с состоянием (Session, User) - в scope='function', наследуясь от тяжелых.
#pytest #testing #qa #bestpractices #python
📲 Мы в MAX
👉@BookPythonmap, filter, reduce ⚡
Привет, друзья! Сегодня расскажу о том, как можно ускорить выполнение кода, заменяя обычные циклы на встроенные функции map(), filter() и reduce(). Эти инструменты позволяют писать более компактный, читаемый и быстрый код.
✅ map()
Функция map() применяется к каждому элементу последовательности и возвращает новый итератор.
❌ Обычный способ:
numbers = [1, 2, 3, 4, 5]
squared = []
for num in numbers:
squared.append(num ** 2)
✅ Быстрее с map():
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x ** 2, numbers))
За счёт того, что map() использует C-оптимизированную логику, код выполняется быстрее.
✅ filter()
Фильтрует элементы последовательности по заданному условию.
❌ Медленный вариант:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens = []
for num in numbers:
if num % 2 == 0:
evens.append(num)
✅ Быстрее с filter():
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens = list(filter(lambda x: x % 2 == 0, numbers))
Такой код читается легче и работает быстрее.
✅ reduce()
Позволяет выполнять кумулятивные операции (например, суммирование, умножение).
❌ Классический способ:
numbers = [1, 2, 3, 4, 5]
product = 1
for num in numbers:
product *= num
✅ Быстрее с reduce():
from functools import reduce
numbers = [1, 2, 3, 4, 5]
product = reduce(lambda x, y: x * y, numbers)
Этот метод полезен, если нужно свести список к одному значению.
💡 Важно: reduce() чаще заменяют sum() или math.prod(), но для сложных операций он остаётся полезным.
Такие функции помогают писать код, который не только быстрее работает, но и легче читается.
📲 Мы в MAX
👉@BookPython
# Хотим создать 3 функции, которые возвращают 0, 1 и 2 соответственно
funcs = []
for i in range(3):
funcs.append(lambda: i)
# Проверяем
results = [f() for f in funcs]
print(results)
# Ожидание: [0, 1, 2]
# Реальность: [2, 2, 2]
Почему так происходит?
Это называется Late Binding (позднее связывание).
В Python замыкания (closures) захватывают переменные по ссылке, а не по значению.
Когда вы объявляете lambda: i, Python не сохраняет текущее число 0, 1 или 2. Он сохраняет инструкцию: «когда меня вызовут, пойди в локальную область видимости, найди переменную с именем i и возьми ее значение».
К моменту, когда вы начинаете вызывать функции из списка results, цикл for уже завершился. Переменная i в этой области видимости навсегда осталась равной 2. Все три лямбды смотрят на одну и ту же переменную i.
Как лечить?
Есть два каноничных способа заставить Python запомнить значение «здесь и сейчас».
1. Аргумент по умолчанию (Hack way)
Значения аргументов по умолчанию вычисляются в момент определения функции.
funcs = []
for i in range(3):
# i=i создает локальную переменную i внутри функции
# и присваивает ей текущее значение i из цикла
funcs.append(lambda i=i: i)
Это работает быстро, но выглядит немного грязно и может сбить с толку линтеры или коллег.
2. functools.partial (Enterprise way)
Более чистый и явный способ. partial создает новый callable-объект, «замораживая» переданные аргументы.
from functools import partial
funcs = []
for i in range(3):
# Здесь значение i фиксируется жестко
funcs.append(partial(lambda x: x, i))
Где это стреляет в реальной жизни?
- Генерация command для кнопок в Tkinter/PyQt.
- Динамическое создание task в asyncio циклах.
- Патчинг тестов в циклах.
Не дайте переменным пережить свое время.
#python #internals #functionalprogramming #gotchas
📲 Мы в MAX
👉@BookPythoncProfile, это детерминированный профайлер. Он хукает каждый вызов функции.
📉 Цена: Оверхед может замедлить приложение в 2-5 раз. На нагруженном проде это означает добить сервис окончательно.
Для Live-систем нужен Sampling Profiler (сэмплирующий профайлер). Золотой стандарт сейчас - py-spy.
Как это работает?
py-spy написан на Rust. Он работает как внешний процесс, который читает память вашего Python-процесса (через системные вызовы, аналогично gdb). Он делает «снимки» стека вызовов с высокой частотой (по дефолту 100 раз в секунду).
✅ Результат: Оверхед стремится к нулю. Код инструментализировать не нужно. Рестарт сервиса не нужен.
Два главных режима работы:
1. Live View (как htop, но для функций)
Посмотреть в реальном времени, в каких функциях процесс проводит больше всего времени.
# Нужно только знать PID процесса
py-spy top --pid 12345
Вы увидите список функций, отсортированный по OwnTime (время внутри функции) и TotalTime (время с учетом дочерних вызовов).
2. Flame Graph (Огненный граф)
Для глубокого анализа лучше записать работу сервиса за период и визуализировать стек.
py-spy record -o profile.svg --pid 12345 --duration 60
Вы получите SVG-файл. Чем шире полоска, тем больше времени занимает функция. Вертикаль - это глубина стека. Сразу видно, кто «съел» процессорное время.
Нюансы для Middle+:
- GIL: py-spy умеет показывать, держит ли функция GIL. Добавьте флаг --gil.
- Docker/K8s: Так как py-spy использует системный вызов ptrace, контейнеру нужны привилегии. В Kubernetes часто нужно добавить securityContext: capabilities: add: ["SYS_PTRACE"] подам, чтобы иметь возможность профилировать их на лету.
#profiling #optimization #pyspy #debugging #python
📲 Мы в MAX
👉@BookPython