Библиотека Python разработчика | Книги по питону
Погружение в CPython и архитектуру. Разбираем неочевидное поведение (GIL, Memory), Best Practices (SOLID, DDD) и тонкости Django/FastAPI. Решаем задачи с подвохом и оптимизируем алгоритмы. 🐍 По всем вопросам @evgenycarter РКН clck.ru/3Ko7Hq
Show more📈 Analytical overview of Telegram channel Библиотека Python разработчика | Книги по питону
Channel Библиотека Python разработчика | Книги по питону (@bookpython) in the Russian language segment is an active participant. Currently, the community unites 18 328 subscribers, ranking 7 307 in the Technologies & Applications category and 36 869 in the Russia region.
📊 Audience metrics and dynamics
Since its creation on невідомо, the project has demonstrated rapid growth, gathering an audience of 18 328 subscribers.
According to the latest data from 04 June, 2026, the channel demonstrates stable activity. Although there has been a change in the number of participants by -86 over the last 30 days and by -1 over the last 24 hours, overall reach remains high.
- Verification status: Not verified
- Engagement rate (ER): The average audience engagement rate is 6.07%. Within the first 24 hours after publication, content typically collects 2.61% reactions from the total number of subscribers.
- Post reach: On average, each post receives 1 112 views. Within the first day, a publication typically gains 479 views.
- Reactions and interaction: The audience actively supports content: the average number of reactions per post is 2.
- Thematic interests: Content is focused on key topics such as numbers, yield, модуль, none, декоратор.
📝 Description and content policy
The author describes the resource as a platform for expressing subjective opinions:
“Погружение в CPython и архитектуру. Разбираем неочевидное поведение (GIL, Memory), Best Practices (SOLID, DDD) и тонкости Django/FastAPI. Решаем задачи с подвохом и оптимизируем алгоритмы. 🐍
По всем вопросам @evgenycarter
РКН clck.ru/3Ko7Hq”
Thanks to the high frequency of updates (latest data received on 05 June, 2026), the channel maintains relevance and a high level of publication reach. Analytics show that the audience actively interacts with content, making it an important point of influence in the Technologies & Applications category.
try ... except Exception, которая предназначена для отлова «любых ошибок». Чтобы безопасно это обработать внутри корутины, приходится писать примерно так:
try:
await action()
except asyncio.CancelledError:
raise
except Exception:
logging.exception('action failed')
👉@BookPythonwith внутри блока if, не заключив туда весь блок with. Это часто приводит к дублированию кода:
def print_whole_file(
*,
path: Optional[str] = None,
file_obj: Optional[TextIO] = None
):
assert path or file_obj
if path:
with open(path) as f:
print(f.read(), end='')
else:
print(file_obj.read(), end='')
Способ борьбы с этой проблемой — использовать ExitStack и вызывать enter_context внутри if:
def print_whole_file(
*,
path: Optional[str] = None,
file_obj: Optional[TextIO] = None
):
assert path or file_obj
with ExitStack() as stack:
if path:
file_obj = stack.enter_context(
open(path)
)
print(file_obj.read(), end='')
Однако более очевидный способ достичь того же — использовать тривиальные менеджеры контекста, которые ничего не делают, когда они не нужны, вместо «настоящих». Начиная с Python 3.7, их можно получить с помощью contextlib.nullcontext:
def print_whole_file(
*,
path: Optional[str] = None,
file_obj: Optional[TextIO] = None
):
assert path or file_obj
if path:
context = open(path)
else:
context = nullcontext(file_obj)
with context as f:
print(f.read(), end='')
👉@BookPythonitertools.tee() создаёт несколько итераторов из одного. Это может быть полезно, если нескольким потребителям нужно читать один и тот же поток.
Пример:
In : a, b, c = tee(iter(input, ''), 3)
In : next(a), next(c)
FIRST
Out: ('FIRST', 'FIRST')
In : next(a), next(b)
SECOND
Out: ('SECOND', 'FIRST')
In : next(a), next(b), next(c)
THIRD
Out: ('THIRD', 'SECOND', 'SECOND')
Данные, которые ещё не были использованы всеми итераторами, сохраняются в памяти. Если часть созданных итераторов ещё не была начата в тот момент, когда другой уже дошёл до конца, это означает, что все сгенерированные элементы будут храниться в памяти для будущего использования.
В таком случае проще и эффективнее использовать list(iter(input, '')), чем tee.
👉@BookPythonrange(2, 10) математически означает [2, 10),
или, говоря на языке Python: [2, 3, 4, 5, 6, 7, 8, 9].
Несмотря на асимметрию, это не ошибка и не случайность.
В этом есть логика: такой подход позволяет "склеивать" два соседних интервала без риска ошибиться на единицу:
[a, c) = [a, b) + [b, c)
Для сравнения, если бы использовались закрытые интервалы, получалось бы так:
[a, c] = [a, b] + [b+1, c]
Эта же идея объясняет, почему индексация начинается с нуля:
[0, N) содержит ровно N элементов.
Эдсгер Дейкстра написал на эту тему отличную статью ещё в 1982 году.
👉@BookPython
In : {**{'a': 1}, 'b': 2, **{'c': 3}}
Out: {'a': 1, 'b': 2, 'c': 3}
In : [1, 2, *[3, 4]]
Out: [1, 2, 3, 4]
Для словарей эта форма ещё более мощная, чем функция dict, так как позволяет переопределять значения:
In : {**{'a': 1, 'b': 1}, 'a': 2, **{'b': 3}}
Out: {'a': 2, 'b': 3}
👉@BookPythonfor и условия if:
In : [(x, y) for x in range(3) for y in range(3)]
Out: [
(0, 0), (0, 1), (0, 2),
(1, 0), (1, 1), (1, 2),
(2, 0), (2, 1), (2, 2)
]
In : [
(x, y)
for x in range(3)
for y in range(3)
if x != 0
if y != 0
]
Out: [(1, 1), (1, 2), (2, 1), (2, 2)]
Кроме того, любое выражение внутри for и if может использовать все переменные, которые были определены ранее:
In : [
(x, y)
for x in range(3)
for y in range(x + 2)
if x != y
]
Out: [
(0, 1),
(1, 0), (1, 2),
(2, 0), (2, 1), (2, 3)
]
Можно смешивать if и for в любом порядке:
In : [
(x, y)
for x in range(5)
if x % 2
for y in range(x + 2)
if x != y
]
Out: [
(1, 0), (1, 2),
(3, 0), (3, 1), (3, 2), (3, 4)
]
👉@BookPython\ в обычной строке имеет специальное значение.
\t — это символ табуляции, \r — возврат каретки и так далее.
Можно использовать *сырые строки* (raw-strings), чтобы отключить это поведение.
r'\t' — это просто обратный слэш и буква t.
Очевидно, что нельзя использовать ' внутри r'...'. Однако его всё ещё можно экранировать через \, но при этом сам \ сохраняется в строке:
>>> print(r'It\'s insane!')
It\'s insane!
Хочешь, я добавлю перевод и к коду, чтобы было ещё понятнее?stdout, вместо того чтобы предоставлять какой-то API, пригодный для использования в программе (например, возвращать строку).
Вместо того чтобы рефакторить такой код, вы можете использовать менеджер контекста contextlib.redirect_stdout, который позволяет временно перенаправить stdout в любой объект, похожий на файл. В связке с io.StringIO это позволяет захватывать вывод в переменную.
from contextlib import redirect_stdout
from io import StringIO
s = StringIO()
with redirect_stdout(s):
print(42)
print(s.getvalue())
Также доступен contextlib.redirect_stderr для перенаправления sys.stderr.
👉@BookPythonx in g.
Python будет итерироваться по g, пока не найдёт x или пока генератор не закончится.
>>> def g():
... print(1)
... yield 1
... print(2)
... yield 2
... print(3)
... yield 3
...
>>> 2 in g()
1
2
True
Однако range() делает для вас больше.
У него переопределён магический метод __contains__, который позволяет оператору in работать с O(1) сложностью:
In [1]: %timeit 10**20 in range(10**30)
375 ns ± 10.7 ns per loop
Имейте в виду, что это не работает для функции xrange() в Python 2.
👉@BookPythonin может использоваться с генераторами: x in g.
Python будет перебирать элементы генератора g, пока не найдёт x или пока генератор не исчерпает элементы.
>>> def g():
... print(1)
... yield 1
... print(2)
... yield 2
... print(3)
... yield 3
...
>>> 2 in g()
1
2
True
Однако range() делает для вас больше.
У него переопределён магический метод __contains__, что позволяет оператору in работать за O(1):
In [1]: %timeit 10**20 in range(10**30)
375 ns ± 10.7 ns per loop
Имейте в виду, что это не работает для функции xrange() в Python 2.
👉@BookPython[]), реализовав магический метод __getitem__.
Вот так можно создать объект, который виртуально содержит бесконечное количество повторяющихся элементов:
class Cycle:
def __init__(self, lst):
self._lst = lst
def __getitem__(self, index):
return self._lst[index % len(self._lst)]
print(Cycle(['a', 'b', 'c'])[100]) # 'b'
Необычность здесь в том, что оператор [] поддерживает особый синтаксис. Его можно использовать не только так — [2], но и так — [2:10], [2:10:2], [2::2] или даже [:].
Обычно это интерпретируется как [start:stop:step], но вы можете задать любую логику для своих объектов.
Что же передаётся в параметр index метода __getitem__, если использовать такой синтаксис? Для этого в Python существуют объекты slice.
class Inspector:
def __getitem__(self, index):
print(index)
Inspector()[1]
# 1
Inspector()[1:2]
# slice(1, 2, None)
Inspector()[1:2:3]
# slice(1, 2, 3)
Inspector()[:]
# slice(None, None, None)
Можно даже комбинировать кортежи и срезы:
Inspector()[:, 0, :]
# (slice(None, None, None), 0, slice(None, None, None))
Объект slice сам по себе ничего не делает — он просто хранит атрибуты start, stop и step:
s = slice(1, 2, 3)
s.start # 1
s.stop # 2
s.step # 3
👉@BookPython
Available now! Telegram Research 2025 — the year's key insights 
