Библиотека Python разработчика | Книги по питону
Погружение в CPython и архитектуру. Разбираем неочевидное поведение (GIL, Memory), Best Practices (SOLID, DDD) и тонкости Django/FastAPI. Решаем задачи с подвохом и оптимизируем алгоритмы. 🐍 По всем вопросам @evgenycarter РКН clck.ru/3Ko7Hq
إظهار المزيد📈 نظرة تحليلية على قناة تيليجرام Библиотека Python разработчика | Книги по питону
تُعد قناة Библиотека Python разработчика | Книги по питону (@bookpython) في القطاع اللغوي الروسية لاعباً نشطاً. يضم المجتمع حالياً 17 970 مشتركاً، محتلاً المرتبة 7 269 في فئة التكنولوجيات والتطبيقات والمرتبة 36 632 في منطقة روسيا.
📊 مؤشرات الجمهور والحراك
منذ تأسيسه في невідомо، حقق المشروع نمواً سريعاً وجمع 17 970 مشتركاً.
بحسب آخر البيانات بتاريخ 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) تحافظ القناة على حداثتها ومستوى وصول مرتفع. وتُظهر التحليلات تفاعلاً نشطاً من الجمهور، ما يجعلها نقطة تأثير مهمة ضمن فئة التكنولوجيات والتطبيقات.
g.close(), но обычно это делает сборщик мусора. Когда вызывается close, в точке, где выполнение генератора было приостановлено, выбрасывается исключение GeneratorExit:
def gen():
try:
yield 1
yield 2
finally:
print('END')
g = gen()
print(next(g)) # выведет '1'
g.close() # выведет 'END'
Обрати внимание на три момента:
1. Нельзя использовать yield при обработке GeneratorExit
Если в блоке finally попытаться сделать yield, возникнет ошибка RuntimeError:
def gen():
try:
yield 1
finally:
yield 3 # ошибка!
g = gen()
next(g)
g.close() # RuntimeError
2. Исключение не выбрасывается, если генератор ещё не запускался
В этом случае генератор просто переходит в состояние остановлен, но finally не выполняется:
def gen():
try:
yield 1
finally:
print('END')
g = gen()
g.close() # ничего не выводит
print(list(g)) # выведет '[]'
3. close() ничего не делает, если генератор уже завершён
Если генератор полностью отработал, close() не вызывает finally повторно и просто игнорируется:
def gen():
try:
yield 1
yield 2
finally:
print('END')
g = gen()
print(list(g)) # ['1', '2']
print('Closing now')
g.close()
# Вывод:
# END
# [1, 2]
# Closing now
👉@BookPythonjson имеет интерфейс командной строки, который может быть полезен для форматирования JSON с помощью одного только Python. Этот модуль называется json.tool и используется следующим образом:
$ echo '{"a": [], "b": "c"}' | python -m json.tool
{
"a": [],
"b": "c"
}
👉@BookPython
class Klass(Parent, arg='arg')
Ключевое слово metaclass зарезервировано для указания метакласса, но остальные аргументы можно использовать свободно.
Ниже приведён пример метакласса, который создаёт класс без одного из атрибутов.
Имя атрибута, который нужно удалить, передаётся через аргумент remove:
class FilterMeta(type):
def __new__(mcs, name, bases, namespace, remove=None, **kwargs):
if remove is not None and remove in namespace:
del namespace[remove]
return super().__new__(mcs, name, bases, namespace)
class A(metaclass=FilterMeta, remove='half'):
def half(x):
return x // 2
half_of_4 = half(4)
half_of_100 = half(100)
a = A()
print(a.half_of_4) # 2
print(a.half_of_100) # 50
a.half # AttributeError
В этом примере метод half удаляется из класса A во время его создания, поэтому попытка обратиться к a.half вызывает AttributeError.
👉@BookPython 1
3 7
5 4 9 8
15 16 17 18 19
В бинарной куче операции вставки и извлечения минимального элемента выполняются за O(log n).
Хранение бинарной кучи в памяти
Полное бинарное дерево обычно хранится в массиве, где:
* левый потомок элемента x[i] находится по индексу 2*i + 1,
* правый потомок - по индексу 2*i + 2.
Пример массива для дерева выше:
[1, 3, 7, 5, 4, 9, 8, 15, 16, 17, 18, 19]Работа с кучей в Python В Python нет отдельного класса для бинарной кучи, но модуль
heapq предоставляет функции, которые позволяют использовать обычный список как бинарную кучу.
Пример использования:
from heapq import *
# Создаём список
heap = [3, 2, 1]
# Преобразуем список в кучу
heapify(heap)
print(heap) # [1, 2, 3]
# Добавляем элемент в кучу
heappush(heap, 0)
print(heap) # [0, 1, 3, 2]
# Извлекаем минимальный элемент
print(heappop(heap)) # 0
# Куча после извлечения
print(heap) # [1, 2, 3]
👉@BookPython__new__. Даже если вы определяете свой собственный __new__ для класса, вы должны вызвать super().__new__(...).
Можно подумать, что object.__new__ — это базовая реализация, отвечающая за создание всех объектов. Но это не совсем так. Существует несколько таких реализаций, и они несовместимы.
Например, у dict есть собственная низкоуровневая реализация __new__, и объекты типов, унаследованных от dict, нельзя создать с помощью object.__new__:
In : class D(dict):
...: pass
...:
In : class A:
...: pass
...:
In : object.__new__(A)
Out: <__main__.A at 0x7f200c8902e8>
In : object.__new__(D)
...
TypeError: object.__new__(D) is not safe,
use D.__new__()
👉@BookPython
from collections import deque
from math import sqrt
class Compose:
def __init__(self):
self._functions = deque()
def __call__(self, *args, **kwargs):
result = None
for f in self._functions:
result = f(*args, **kwargs)
args = [result]
kwargs = dict()
return result
def __rshift__(self, f):
self._functions.append(f)
return self
def __lshift__(self, f):
self._functions.appendleft(f)
return self
compose = Compose
sqrt_abs = (compose() << sqrt << abs)
sqrt_abs2 = (compose() >> abs >> sqrt)
print(sqrt_abs(-4)) # 2.0
print(sqrt_abs2(-4)) # 2.0
Объяснение:
<< — добавляет функцию в начало цепочки (выполняется первой).
>> — добавляет функцию в конец цепочки (выполняется последней).
В примере sqrt_abs(-4) сначала берёт abs(-4) → 4, а затем sqrt(4) → 2.0.
sqrt_abs2(-4) делает то же самое, но функции добавлены в другом порядке.
👉@BookPython__class__:
>>> [1, 2].__class__
<class 'list'>
Однако более привычный способ получить класс — использовать функцию type.
Кроме того, это единственный способ, который работает со старыми стилями классов.
>>> type([1, 2])
<class 'list'>
Если вы хотите проверить, является ли объект экземпляром заданного класса, следует использовать isinstance, а не сравнение:
>>> class A:
... pass
...
>>> class B(A):
... pass
...
>>> type(B())
<class '__main__.B'>
>>> isinstance(B(), A)
True
👉@BookPython
try:
cache
except NameError:
cache = {}
На первый взгляд, нет смысла писать что-то подобное. Переменная cache однозначно вызовет NameError в начале выполнения модуля, так как она ещё не была определена.
Однако ситуация меняется, если модуль перезагружается. В этом случае словарь, содержащий все атрибуты модуля, переиспользуется, что даёт возможность модулю сохранить значения из предыдущей версии.
Если модуль изначально спроектирован с учётом перезагрузки, он может использовать эту особенность. Например, приведённый выше код позволяет сохранить кэш между перезагрузками модуля.
👉@BookPythonmath.nan.
NaN не равен ничему, включая самого себя:
>>> math.nan == math.nan
False
Кроме того, объект NaN не является уникальным — можно получить несколько разных объектов NaN из разных источников:
>>> float('nan')
nan
>>> float('nan') is float('nan')
False
Это означает, что обычно нельзя использовать NaN в качестве ключа словаря:
>>> d = {}
>>> d[float('nan')] = 1
>>> d[float('nan')] = 2
>>> d
{nan: 1, nan: 2}
👉@BookPythonNone равен None, поэтому может показаться, что проверку на None можно делать через ==:
ES_TAILS = ('s', 'x', 'z', 'ch', 'sh')
def make_plural(word, exceptions=None):
if exceptions == None: # ← ← ←
exceptions = {}
if word in exceptions:
return exceptions[word]
elif any(word.endswith(t) for t in ES_TAILS):
return word + 'es'
elif word.endswith('y'):
return word[0:-1] + 'ies'
else:
return word + 's'
exceptions = dict(
mouse='mice',
)
print(make_plural('python'))
print(make_plural('bash'))
print(make_plural('ruby'))
print(make_plural('mouse', exceptions=exceptions))
Однако так делать неправильно. Действительно, None равен None, но не только он может быть равен None. Пользовательские объекты тоже могут вернуть True при сравнении с None через ==:
class A:
def __eq__(self, other):
return True
print(A() == None) # True
print(A() is None) # False
Правильный способ проверки на None — использовать is None.
👉@BookPython