Библиотека Python разработчика | Книги по питону
Погружение в CPython и архитектуру. Разбираем неочевидное поведение (GIL, Memory), Best Practices (SOLID, DDD) и тонкости Django/FastAPI. Решаем задачи с подвохом и оптимизируем алгоритмы. 🐍 По всем вопросам @evgenycarter РКН clck.ru/3Ko7Hq
نمایش بیشتر📈 تحلیل کانال تلگرام Библиотека Python разработчика | Книги по питону
کانال Библиотека Python разработчика | Книги по питону (@bookpython) در بخش زبانی روسی بازیگری فعال است. در حال حاضر جامعه شامل 17 973 مشترک است و جایگاه 7 274 را در دسته فناوری و برنامهها و رتبه 36 654 را در منطقه روسيا دارد.
📊 شاخصهای مخاطب و پویایی
از زمان ایجاد در невідомо، پروژه رشد سریعی داشته و 17 973 مشترک جذب کرده است.
بر اساس آخرین دادهها در تاریخ 28 اکتبر, 2026، کانال فعالیت پایداری دارد. در ۳۰ روز گذشته تغییر اعضا برابر -96 و در ۲۴ ساعت گذشته برابر -2 بوده و همچنان دسترسی گستردهای حفظ شده است.
- وضعیت تأیید: تأیید نشده
- نرخ تعامل (ER): میانگین تعامل مخاطب 5.41% است و در ۲۴ ساعت نخست پس از انتشار، محتوا معمولاً 2.64% واکنش نسبت به کل مشترکان کسب میکند.
- دسترسی پستها: هر پست به طور میانگین 973 بازدید دریافت میکند. در اولین روز معمولاً 475 بازدید جمعآوری میشود.
- واکنشها و تعامل: مخاطبان بهطور فعال حمایت میکنند؛ میانگین واکنش به هر پست 4 است.
- علایق موضوعی: محتوا بر موضوعات کلیدی مانند numbers, yield, модуль, none, декоратор تمرکز دارد.
📝 توضیح و سیاست محتوایی
نویسنده این فضا را محل بیان دیدگاههای شخصی توصیف میکند:
“Погружение в CPython и архитектуру. Разбираем неочевидное поведение (GIL, Memory), Best Practices (SOLID, DDD) и тонкости Django/FastAPI. Решаем задачи с подвохом и оптимизируем алгоритмы. 🐍
По всем вопросам @evgenycarter
РКН clck.ru/3Ko7Hq”
به لطف بهروزرسانیهای پرتکرار (آخرین داده در تاریخ 29 اکتبر, 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