Библиотека Python разработчика | Книги по питону
Погружение в CPython и архитектуру. Разбираем неочевидное поведение (GIL, Memory), Best Practices (SOLID, DDD) и тонкости Django/FastAPI. Решаем задачи с подвохом и оптимизируем алгоритмы. 🐍 По всем вопросам @evgenycarter РКН clck.ru/3Ko7Hq
显示更多📈 Telegram 频道 Библиотека Python разработчика | Книги по питону 的分析概览
频道 Библиотека Python разработчика | Книги по питону (@bookpython) 俄语 语言赛道中的 是活跃参与者。目前社区聚集了 18 326 名订阅者,在 技术与应用 类别中位列第 7 317,并在 俄罗斯 地区排名第 36 872 位。
📊 受众指标与增长动态
自 невідомо 创建以来,项目保持高速增长,吸引了 18 326 名订阅者。
根据 05 六月, 2026 的最新数据,频道保持稳定运转。过去 30 天订阅人数变化为 -86,过去 24 小时变化为 -1,整体触达仍然可观。
- 认证状态: 未认证
- 互动率 (ER): 平均受众互动率为 6.08%。内容发布后 24 小时内通常能获得 2.60% 的反应,占订阅者总量。
- 帖子覆盖: 每篇帖子平均可获得 1 114 次浏览,首日通常累积 477 次浏览。
- 互动与反馈: 受众积极参与,单帖平均反应数为 2。
- 主题关注点: 内容集中在 numbers, yield, модуль, none, декоратор 等核心主题上。
📝 描述与内容策略
作者将该频道定位为表达主观观点的平台:
“Погружение в CPython и архитектуру. Разбираем неочевидное поведение (GIL, Memory), Best Practices (SOLID, DDD) и тонкости Django/FastAPI. Решаем задачи с подвохом и оптимизируем алгоритмы. 🐍
По всем вопросам @evgenycarter
РКН clck.ru/3Ko7Hq”
凭借高频更新(最新数据采集于 06 六月, 2026),频道始终保持新鲜度与高覆盖。分析显示受众积极互动,使其成为 技术与应用 类别中的关键影响点。
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
现已上线!2025 年 Telegram 研究 — 年度关键洞察 
