Библиотека Python разработчика | Книги по питону
Погружение в CPython и архитектуру. Разбираем неочевидное поведение (GIL, Memory), Best Practices (SOLID, DDD) и тонкости Django/FastAPI. Решаем задачи с подвохом и оптимизируем алгоритмы. 🐍 По всем вопросам @evgenycarter РКН clck.ru/3Ko7Hq
Ko'proq ko'rsatish📈 Telegram kanali Библиотека Python разработчика | Книги по питону analitikasi
Библиотека Python разработчика | Книги по питону (@bookpython) Rus til segmentidagi kanali faol ishtirokchi. Hozirda hamjamiyat 17 973 obunachidan iborat bo'lib, Texnologiyalar & Aralashmalar toifasida 7 274-o'rinni va Rossiya mintaqasida 36 654-o'rinni egallagan.
📊 Auditoriya ko‘rsatkichlari va dinamika
невідомо sanasidan buyon loyiha tez o‘sib, 17 973 obunachiga ega bo‘ldi.
28 Oktabr, 2026 dagi oxirgi ma’lumotlarga ko‘ra kanal barqaror faollikka ega. Oxirgi 30 kunda obunachilar soni -96 ga, so‘nggi 24 soatda esa -2 ga o‘zgardi va umumiy qamrov yuqori darajada qolmoqda.
- Tasdiqlash holati: Tasdiqlanmagan
- Jalb etish (ER): Auditoriya o‘rtacha 5.41% darajada jalb etiladi. Nashrdan keyingi dastlabki 24 soatda kontent odatda umumiy obunachilar sonining 2.64% ini tashkil etuvchi reaksiyalarni to‘playdi.
- Post qamrovi: Har bir post o‘rtacha 973 marta ko‘riladi; birinchi sutkada odatda 475 ta ko‘rish yig‘iladi.
- Reaksiyalar va o‘zaro ta’sir: Auditoriya faol: har bir postga o‘rtacha 4 ta reaksiya keladi.
- Tematik yo‘nalishlar: Kontent numbers, yield, модуль, none, декоратор kabi asosiy mavzularga jamlangan.
📝 Tavsif va kontent siyosati
Muallif resursni shaxsiy fikrni ifoda etish maydoni sifatida ta’riflaydi:
“Погружение в CPython и архитектуру. Разбираем неочевидное поведение (GIL, Memory), Best Practices (SOLID, DDD) и тонкости Django/FastAPI. Решаем задачи с подвохом и оптимизируем алгоритмы. 🐍
По всем вопросам @evgenycarter
РКН clck.ru/3Ko7Hq”
Yuqori yangilanish chastotasi (oxirgi ma’lumot 29 Oktabr, 2026 da olingan) sababli kanal doimo dolzarb va katta qamrovli bo‘lib qoladi. Analitika auditoriya kontent bilan faol hamkorlik qilishini, uni Texnologiyalar & Aralashmalar toifasidagi muhim ta’sir nuqtasiga aylantirishini ko‘rsatadi.
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