Библиотека 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 326 subscribers, ranking 7 317 in the Technologies & Applications category and 36 872 in the Russia region.
📊 Audience metrics and dynamics
Since its creation on невідомо, the project has demonstrated rapid growth, gathering an audience of 18 326 subscribers.
According to the latest data from 05 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.08%. Within the first 24 hours after publication, content typically collects 2.60% reactions from the total number of subscribers.
- Post reach: On average, each post receives 1 114 views. Within the first day, a publication typically gains 477 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 06 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.
map вызывает другую функцию для каждого элемента итерируемого объекта. Это значит, что функция должна принимать одно значение в качестве аргумента:
In : list(map(lambda x: x ** 2, [1, 2, 3]))
Out: [1, 4, 9]
Однако если каждый элемент итерируемого объекта — это кортеж, было бы удобно передавать каждый элемент кортежа как отдельный аргумент. В Python 2 это было возможно благодаря распаковке параметров кортежа (обратите внимание на скобки):
>>> map(lambda (a, b): a + b, [(1, 2), (3, 4)])
[3, 7]
В Python 3 эта возможность исчезла, но есть другое решение — itertools.starmap. Она распаковывает кортежи за вас, будто функция вызывается со звёздочкой: f(*arg) (отсюда и название функции):
from itertools import starmap
In [3]: list(starmap(lambda a, b: a + b, [(1, 2), (3, 4)]))
Out[3]: [3, 7]
👉@BookPythonsuper() позволяет обращаться к родительскому (базовому) классу. Это может быть очень полезно в случаях, когда производный класс хочет добавить что-то к реализации метода, а не полностью переопределять его:
class BaseTestCase(TestCase):
def setUp(self):
self._db = create_db()
class UserTestCase(BaseTestCase):
def setUp(self):
super().setUp()
self._user = create_user()
Имя функции super не означает "отличный" или "очень хороший". В данном контексте слово super означает "выше" (как, например, в слове superintendent — заведующий). Несмотря на это, super() не всегда ссылается на базовый класс — он может вернуть и "соседний" класс. Более точным названием была бы, возможно, функция next(), так как возвращается следующий класс согласно цепочке разрешения методов (MRO — Method Resolution Order).
Пример:
class Top:
def foo(self):
return 'top'
class Left(Top):
def foo(self):
return super().foo()
class Right(Top):
def foo(self):
return 'right'
class Bottom(Left, Right):
pass
# выводит 'right'
print(Bottom().foo())
Обрати внимание: результат работы super() может отличаться в зависимости от MRO вызвавшего объекта.
>>> Bottom().foo()
'right'
>>> Left().foo()
'top'
👉@BookPython
$ echo /li*
/lib /lib64
Python поддерживает globbing с помощью модуля glob. Однако есть важное замечание: оболочка возвращает сам шаблон, если файлы не найдены, а Python — нет:
$ echo /zz**
/zz**
$ python -c 'from glob import glob; print(glob("/zz**"))'
[]
👉@BookPythonnext(gen). В Python 3 вы также можете отправлять значения обратно в генератор с помощью g.send(x). Но существует техника, которой вы, вероятно, не пользуетесь каждый день, а возможно, и вовсе не знаете: выбрасывание исключений внутри генератора.
С помощью gen.throw(e) можно выбросить исключение в той точке, где генератор gen приостановлен — то есть на инструкции yield. Если генератор обрабатывает это исключение, gen.throw(e) возвращает следующее значение, полученное через yield (или выбрасывает StopIteration, если генератор завершён). Если генератор не перехватывает исключение, оно пробрасывается обратно к вызывающему коду.
def gen():
try:
yield 1
except ValueError:
yield 2
g = gen()
next(g)
# Out: 1
g.throw(ValueError)
# Out: 2
g.throw(RuntimeError('TEST'))
# RuntimeError: TEST
Эта техника позволяет более точно управлять поведением генератора — не только передавать данные внутрь, но и, например, сообщать о проблемах со значениями, полученными через yield. Однако такие случаи бывают редко, и встретить g.throw в дикой природе почти невозможно.
Тем не менее, декоратор @contextmanager из модуля contextlib использует именно такую технику, позволяя коду внутри контекста перехватывать исключения.
from contextlib import contextmanager
@contextmanager
def atomic():
print('BEGIN')
try:
yield
except Exception:
print('ROLLBACK')
else:
print('COMMIT')
with atomic():
print('ERROR')
raise RuntimeError()
BEGIN
ERROR
ROLLBACK
👉@BookPythonunicodedata:
import unicodedata
modes = [
# Сжать канонически эквивалентные
'NFC',
# Расширить канонически эквивалентные
'NFD',
# Сжать совместимые
'NFKC',
# Расширить совместимые
'NFKD',
]
s = 'ff + ö'
for mode in modes:
norm = unicodedata.normalize(mode, s)
print('\t'.join([
mode,
norm,
str(len(norm.encode('utf8'))),
]))
Результат:
NFC ff + ö 8 NFD ff + ö 9 NFKC ff + ö 7 NFKD ff + ö 8👉@BookPython
print()? Вот тут и приходит на помощь наш герой — универсальный логгер-декоратор:
import functools
def log_calls(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"[CALL] {func.__name__} args={args} kwargs={kwargs}")
result = func(*args, **kwargs)
print(f"[RETURN] {func.__name__} -> {result}")
return result
return wrapper
Пример использования:
@log_calls
def multiply(a, b):
return a * b
multiply(3, 5)
📌 Вывод:
[CALL] multiply args=(3, 5) kwargs={}
[RETURN] multiply -> 15
Такой декоратор можно подключить временно на любую функцию — и сразу видеть, что происходит у вас в коде. Это особенно удобно при работе со сторонними библиотеками или когда вы разбираетесь в чужом проекте.
Кстати, с небольшими изменениями можно направить вывод не в print(), а в logging, или даже сохранять в файл — по вкусу.
Пользуетесь такими декораторами? Или у вас свой лайфхак?
👉@BookPython__init__, возможно, будет лучше передавать их как аргументы и использовать фабричный метод. Это позволяет разделить бизнес-логику и технические детали создания объектов.
В этом примере __init__ принимает host и port для создания подключения к базе данных:
class Query:
def __init__(self, host, port):
self._connection = Connection(host, port)
Возможный рефакторинг:
class Query:
def __init__(self, connection):
self._connection = connection
@classmethod
def create(cls, host, port):
return cls(Connection(host, port))
Такой подход имеет как минимум следующие преимущества:
• Упрощает внедрение зависимостей. В тестах можно использовать Query(FakeConnection()).
• Класс может иметь столько фабричных методов, сколько нужно; подключение может создаваться не только по host и port, но и путём клонирования другого подключения, чтения конфигурационного файла или объекта, использования значения по умолчанию и т.д.
• Такие фабричные методы можно сделать асинхронными; это невозможно для __init__.
👉@BookPythonencoding= функции open, либо читать «сырые» байты, добавив b к режиму открытия файла.
👉@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.
👉@BookPythonobj.x = y, нельзя быть уверенным, что атрибут x объекта obj действительно станет равным y. Протокол дескрипторов в Python позволяет определить, как будет обрабатываться присваивание атрибутов.
class Descriptor:
def __set__(self, obj, value):
obj.test = value
class A:
x = Descriptor()
В этом примере x напрямую никогда не присваивается значение — вместо этого устанавливается атрибут test:
>>> a = A()
>>> a.x = 42
>>> a.test
42
>>> a.x
<__main__.Descriptor at 0x7ff7baef51d0>
Если всё же нужно напрямую изменить значение x, например, в тестах или при использовании метапрограммирования, придётся обращаться напрямую к __dict__:
>>> a.__dict__['x'] = 42
>>> a.x
42
👉@BookPythonEllipsis, которую также можно записать как .... Эта константа не имеет особого значения для интерпретатора, но используется в местах, где такой синтаксис выглядит уместно.
Библиотека NumPy поддерживает Ellipsis в качестве аргумента __getitem__, например: x[...] возвращает все элементы массива x.
PEP 484 придаёт Ellipsis дополнительное значение: Callable[..., type] — это способ определить тип вызываемых объектов без указания типов аргументов.
Наконец, ... можно использовать, чтобы обозначить, что функция ещё не реализована. Это абсолютно валидный код на Python:
def x():
...
👉@BookPython
Available now! Telegram Research 2025 — the year's key insights 
