Библиотека Python разработчика | Книги по питону
Погружение в CPython и архитектуру. Разбираем неочевидное поведение (GIL, Memory), Best Practices (SOLID, DDD) и тонкости Django/FastAPI. Решаем задачи с подвохом и оптимизируем алгоритмы. 🐍 По всем вопросам @evgenycarter РКН clck.ru/3Ko7Hq
Больше📈 Аналитический обзор Telegram-канала Библиотека Python разработчика | Книги по питону
Канал Библиотека Python разработчика | Книги по питону (@bookpython) языкового сегмента Русский является активным участником. Сейчас сообщество объединяет 17 967 подписчиков, занимая 7 269 место в категории Технологии и приложения и 36 632 место в регионе Россия.
📊 Показатели аудитории и динамика
С момента создания невідомо проект демонстрирует стремительный рост, собрав аудиторию из 17 967 подписчиков.
Согласно последним данным от 29 октября, 2026, канал показывает стабильную активность. За последние 30 дней изменение числа участников составило -98, а за последние 24 часа — -6, при этом общий охват остаётся высоким.
- Статус верификации: Не верифицирован
- Уровень вовлечённости (ER): Средний показатель вовлечённости аудитории составляет 5.47%. В первые 24 часа после публикации контент обычно набирает 2.71% реакций от общего числа подписчиков.
- Охват публикаций: В среднем каждый пост получает 983 просмотров. В течение первых суток публикация набирает 487 просмотров.
- Реакции и взаимодействия: Аудитория активно поддерживает контент: среднее количество реакций на один пост — 4.
- Тематические интересы: Контент сосредоточен на ключевых темах, таких как numbers, yield, модуль, none, декоратор.
📝 Описание и контентная политика
Автор описывает ресурс как площадку для выражения субъективного мнения:
“Погружение в CPython и архитектуру. Разбираем неочевидное поведение (GIL, Memory), Best Practices (SOLID, DDD) и тонкости Django/FastAPI. Решаем задачи с подвохом и оптимизируем алгоритмы. 🐍
По всем вопросам @evgenycarter
РКН clck.ru/3Ko7Hq”
Благодаря высокой частоте обновлений (последние данные получены 30 октября, 2026) канал поддерживает актуальность и высокий уровень охвата публикаций. Аналитика показывает, что аудитория активно взаимодействует с контентом, что делает его важной точкой влияния в категории Технологии и приложения.
__bases__; он возвращает непосредственных родителей класса:
class A:
pass
class B(A):
pass
class C(A):
pass
class D(B, C):
pass
print(D.__bases__)
# (<class '__main__.B'>, <class '__main__.C'>)
Второй —
class B он возвращает кортеж со всеми классами, которые задействованы при разрешении методов (отсюда и название), то есть родителей, их родителей и так далее:
print(D.__mro__)
# (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
👉@BookPython
(x for x in range(100) if random() > 0.5)
Если вы пишете свой итерируемый объект и хотите добавить такую подсказку, определите метод __length_hint__. Если же длина известна точно, лучше использовать len.
Если вы используете итерируемый объект и хотите узнать его ожидаемую длину, применяйте функцию operator.length_hint.
👉@BookPython
from itertools import tee
def neighbours(iterable, n):
neighbours = tee(iterable, n)
for i, neighbour in enumerate(neighbours):
for _ in range(i):
next(neighbour)
return zip(*neighbours)
fibb = [1, 1, 2, 3, 5, 8, 13, 21]
for a, b, c in neighbours(fibb, 3):
assert c == a + b
В этом примере мы разветвляем исходный итерируемый объект с помощью tee, затем сдвигаем полученные итераторы с помощью next, чтобы второй начинался со второго элемента исходного итерируемого объекта, а третий — с третьего, и затем объединяем их обратно с помощью zip.
👉@BookPython IndexError, и KeyError, вы можете и должны использовать LookupError — их общего предка. Это оказывается полезным при работе со сложными вложенными данными:
try:
db_host = config['databases'][0]['hosts'][0]
except LookupError:
db_host = 'localhost'
👉@BookPython
In : p = Pair(1, 2)
In : p
Out: Pair(1, 2)
In : p.right = p
In : p
Out: [...]
RecursionError: maximum recursion depth exceeded while calling a Python object
Чтобы просто решить эту проблему, можно использовать декоратор reprlib.recursive_repr:
@reprlib.recursive_repr()
def **repr**(self):
class_name = type(self).**name**
return f'{class_name}({self.left!r}, {self.right!r})'
Теперь всё работает:
In : p = Pair(1, 2)
In : p.right = p
In : p
Out: Pair(1, ...)
👉@BookPython
class truncater:
def __init__(self, length):
self._length = length
def __call__(self, s):
return s[0:self._length]
print(truncater(4)('abcdabcd')) # abcd
Поскольку декоратор по сути является функцией высшего порядка, его также можно реализовать в виде вызываемого объекта вместо функции:
class cached:
def __init__(self, func):
self._func = func
self._cache = {}
def __call__(self, arg):
if arg not in self._cache:
self._cache[arg] = self._func(arg)
return self._cache[arg]
@cached
def sqr(x):
return x * x
👉@BookPython
class A: pass
a = A()
a.x = 1
a.__dict__
# {'x': 1}
При прямом доступе к этому словарю можно даже создать атрибуты, которые не являются допустимыми идентификаторами Python (то есть получить их через стандартный синтаксис obj.attr не получится):
a.__dict__[' '] = ' '
getattr(a, ' ')
# ' '
Можно также попросить Python хранить атрибуты непосредственно в памяти (как у простых структур C) с помощью slots. Это экономит память и немного ускоряет доступ к атрибутам, так как не происходит поиска в словаре.
class Point:
__slots__ = ['x', 'y']
Есть несколько моментов, которые нужно помнить при использовании slots. Во-первых, нельзя задавать атрибуты, не указанные в slots. Во-вторых, если класс наследуется от класса с slots, его slots не перекрывают родительские, а добавляются к ним:
class Parent: __slots__ = ['x']
class Child(Parent): __slots__ = ['y']
c = Child()
c.x = 1
c.y = 2
В-третьих, нельзя наследоваться сразу от двух разных классов с непустыми slots, даже если они совпадают.
Помни, что slots предназначены для оптимизации, а не для ограничения набора атрибутов.
👉@BookPythonos.path. Модуль содержит множество функций, которые обрабатывают строки как пути и выполняют полезные операции, такие как объединение путей и прочее:
>>> import os.path
>>> os.path.join('/usr', 'local')
'/usr/local'
>>> os.path.dirname('/var/log')
'/var'
Однако, начиная с Python 3.4, доступен новый модуль pathlib, предлагающий объектно-ориентированный подход:
>>> from pathlib import Path
>>> Path('/usr') / Path('local')
PosixPath('/usr/local')
>>> Path('/usr') / 'local'
PosixPath('/usr/local')
>>> Path('/var/log').parent
PosixPath('/var')
>>> Path('/var/log').parent.name
'var'
👉@BookPythonmatch-case
Теперь можно использовать «захват» значений прямо в паттернах:
def http_status(code):
match code:
case 200 | 201 | 202 as ok:
return f"Success: {ok}"
case 400 as bad | 404 as bad:
return f"Client error: {bad}"
case _:
return "Other"
Большая гибкость и меньше «шаблонных» переменных!
2️⃣ Новый оператор f”{…=}" для отладки
Позволяет вывести и имя, и значение переменной в одной строке:
user = "Alice"
age = 29
print(f"{user=}, {age=}")
# Выведет: user='Alice', age=29
Больше никаких лишних print("user", user)!
3️⃣ Оптимизация работы с памятью и скорость
Команда CPython продолжает ускорение интерпретатора:
* Выделение объектов стало быстрее
* Сборщик мусора реже «паузит» приложение
Это особенно заметно в тяжёлых сервисах и бэкендах.
4️⃣ Новые API для типов
Добавили typing.Self и более гибкие Generic-типизации:
from typing import Self
class Builder:
def set_name(self, name: str) -> Self:
self.name = name
return self
b = Builder().set_name("Demo")
Удобнее писать цепочки вызовов без «# type: ignore»!
💡 Что попробовать прямо сейчас?
1. Установить Python 3.12 pre-release:
pyenv install 3.12.0b4
2. Переписать пару функций с match-case.
3. Пощупать f"{var=}" в дебаге.
👉@BookPython
>>> def enclose(gen, before='{', after='}'):
... yield before
... for x in gen:
... yield x
... yield after
...
>>> list(enclose(range(5)))
['{', 0, 1, 2, 3, 4, '}']
Однако предпочтительнее использовать yield from:
>>> def enclose(gen, before='{', after='}'):
... yield before
... yield from gen
... yield after
yield from не только работает быстрее, но и автоматически обрабатывает передачу значений во вложенные генераторы, возврат значений из генераторов и даже выброс исключений внутри вложенного генератора.
👉@BookPython
def append_length(lst=[]):
lst.append(len(lst))
return lst
print(append_length([1, 2])) # [1, 2, 2]
print(append_length()) # [0]
print(append_length()) # [0, 1]
Однако в некоторых случаях, например при реализации кешей, такое поведение может быть полезным:
def fact(x, cache={0: 1}):
if x not in cache:
cache[x] = x * fact(x - 1)
return cache[x]
print(fact(5))
В этом примере мы сохраняем вычисленные значения факториала внутри значения аргумента по умолчанию. Причём к этому значению даже можно обратиться напрямую:
>>> fact.__defaults__
({0: 1, 1: 1, 2: 2, 3: 6, 4: 24, 5: 120},)
👉@BookPython