Библиотека 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 18 329 obunachidan iborat bo'lib, Texnologiyalar & Aralashmalar toifasida 7 317-o'rinni va Rossiya mintaqasida 36 872-o'rinni egallagan.
📊 Auditoriya ko‘rsatkichlari va dinamika
невідомо sanasidan buyon loyiha tez o‘sib, 18 329 obunachiga ega bo‘ldi.
05 Iyun, 2026 dagi oxirgi ma’lumotlarga ko‘ra kanal barqaror faollikka ega. Oxirgi 30 kunda obunachilar soni -86 ga, so‘nggi 24 soatda esa -1 ga o‘zgardi va umumiy qamrov yuqori darajada qolmoqda.
- Tasdiqlash holati: Tasdiqlanmagan
- Jalb etish (ER): Auditoriya o‘rtacha 6.08% darajada jalb etiladi. Nashrdan keyingi dastlabki 24 soatda kontent odatda umumiy obunachilar sonining 2.60% ini tashkil etuvchi reaksiyalarni to‘playdi.
- Post qamrovi: Har bir post o‘rtacha 1 114 marta ko‘riladi; birinchi sutkada odatda 477 ta ko‘rish yig‘iladi.
- Reaksiyalar va o‘zaro ta’sir: Auditoriya faol: har bir postga o‘rtacha 2 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 07 Iyun, 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.
a < b означает, что a является подмножеством b:
>>> {1} < {1, 2}
True
>>> {1} < {2, 3}
False
Это означает, что множества частично упорядочены, то есть существуют такие a и b, что и a < b, и b < a — ложны:
>>> {1} < {2, 3}
False
>>> {1} > {2, 3}
False
Некоторые функции, такие как min, max и sorted, требуют полного порядка, поэтому их применение к списку множеств может дать неожиданные результаты:
>>> min([{1}, {2}])
{1}
>>> min([{2}, {1}])
{2}
👉@BookPythonexcept автоматически добавляет перехваченное исключение в атрибут __context__ нового исключения. Это приводит к тому, что оба исключения отображаются в traceback:
try:
1 / 0
except ZeroDivisionError:
raise ValueError('Zero!')
Результат выполнения:
Traceback (most recent call last):
File "test.py", line 2, in <module>
1 / 0
ZeroDivisionError: division by zero
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "test.py", line 4, in <module>
raise ValueError('Zero!')
ValueError: Zero!
Вы также можете добавить __cause__ к любому исключению с помощью выражения raise ... from:
division_error = None
try:
1 / 0
except ZeroDivisionError as e:
division_error = e
raise ValueError('Zero!') from division_error
Результат выполнения:
Traceback (most recent call last):
File "test.py", line 4, in <module>
1 / 0
ZeroDivisionError: division by zero
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "test.py", line 8, in <module>
raise ValueError('Zero!') from division_error
ValueError: Zero!
👉@BookPythonobj.x — это вызов метода x. В Java рекомендуется делать все атрибуты приватными и писать тривиальные геттеры, например: public int getX() { return this.x; }.
Python предлагает решение, которое в некотором роде похоже на то, что есть в Ruby. Вы можете определить свойство (`property`), чтобы obj.x вызывал метод вместо прямого возврата атрибута x.
class Example:
def __init__(self, x):
self._x = x
@property
def x(self):
return self._x
👉@BookPython
class GrandParent:
pass
class Parent1(GrandParent):
pass
class Parent2(GrandParent):
pass
class Child(Parent1, Parent2):
pass
В каком порядке будет производиться поиск метода Child.x()? Наивный подход заключается в рекурсивном поиске через все родительские классы, что даст порядок: Child, Parent1, GrandParent, Parent2. Такой метод используется во многих языках программирования, однако он не совсем логичен, так как Parent2 более специфичен, чем GrandParent, и его нужно проверять раньше.
Чтобы исправить эту проблему, Python использует линеаризацию C3 (C3 superclass linearization), алгоритм, который всегда ищет метод сначала во всех дочерних классах, а затем уже в родительских.
Пример вывода MRO (Method Resolution Order):
In : Child.__mro__
Out:
(__main__.Child,
__main__.Parent1,
__main__.Parent2,
__main__.GrandParent,
object)
👉@BookPythonfor и with могут быть асинхронными. async with использует магические методы __aenter__ и __aexit__, а async for — методы __aiter__ и __anext__. Все они асинхронные, и внутри них можно использовать await:
import asyncio
class Sleep:
def __init__(self, t):
self._t = t
async def __aenter__(self):
await asyncio.sleep(self._t / 2)
async def __aexit__(self, *args):
await asyncio.sleep(self._t / 2)
async def main():
async with Sleep(2):
print('*')
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Когда вы реализуете метод __iter__, часто вместо написания итератора с методом __next__ используется оператор yield, который делает метод __iter__ генератором:
class Bracketed:
def __init__(self, data):
self._data = data
def __iter__(self):
for x in self._data:
yield '({})'.format(x)
print(list(Bracketed([1, 2, 3])))
# ['(1)', '(2)', '(3)']
PEP 525 позволяет делать то же самое с методом __aiter__. Наличие операторов yield и await в теле функции делает её асинхронным генератором. В то время как await используется для взаимодействия с циклом событий, yield управляет работой с for:
import asyncio
class Slow:
def __init__(self, data, t=1):
self._data = data
self._t = t
async def __aiter__(self):
for x in self._data:
await asyncio.sleep(self._t)
yield x
async def main():
async for x in Slow([1, 2, 3]):
print(x)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
👉@BookPythonthreading решает эту проблему с помощью объекта threading.local(), который является потокобезопасным. Вы можете хранить данные, просто устанавливая атрибуты, например: threading.local().symbol = '@'.
Но оба этих подхода не подходят для асинхронных приложений, где функции не только вызываются, но и могут быть приостановлены с помощью await. Если корутина выполняет await, цикл событий может переключиться на другую корутину из совершенно другой цепочки вызовов. Это приведет к некорректной работе, как в следующем примере:
import asyncio
import sys
global_symbol = '.'
async def indication(timeout):
while True:
print(global_symbol, end='')
sys.stdout.flush()
await asyncio.sleep(timeout)
async def sleep(t, indication_t, symbol='.'):
loop = asyncio.get_event_loop()
global global_symbol
global_symbol = symbol
loop.create_task(indication(indication_t))
await asyncio.sleep(t)
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(
sleep(1, 0.1, '0'),
sleep(1, 0.1, 'a'),
sleep(1, 0.1, 'b'),
sleep(1, 0.1, 'c'),
))
Решить эту проблему можно, если цикл событий будет устанавливать и восстанавливать контекст каждый раз, когда он возобновляет выполнение корутины. Модуль aiotask_context реализует это, изменяя способ создания задач с помощью loop.set_task_factory. Пример рабочей версии:
import asyncio
import sys
import aiotask_context as context
async def indication(timeout):
while True:
print(context.get('symbol'), end='')
sys.stdout.flush()
await asyncio.sleep(timeout)
async def sleep(t, indication_t, symbol='.'):
loop = asyncio.get_event_loop()
context.set(key='symbol', value=symbol)
loop.create_task(indication(indication_t))
await asyncio.sleep(t)
loop = asyncio.get_event_loop()
loop.set_task_factory(context.task_factory)
loop.run_until_complete(asyncio.gather(
sleep(1, 0.1, '0'),
sleep(1, 0.1, 'a'),
sleep(1, 0.1, 'b'),
sleep(1, 0.1, 'c'),
))
👉@BookPythonawait obj (или yield from obj до Python 3.6). Объект obj должен быть другой корутиной, объектом asyncio.Future или любым пользовательским объектом, похожим на Future (любой объект, у которого определен метод __await__).
async def coroutine():
await another_coroutine()
async def another_coroutine():
future = asyncio.Future()
await future
loop = asyncio.get_event_loop()
loop.run_until_complete(coroutine())
Когда корутина ожидает (await) другую корутину, вторая начинает выполняться вместо первой. Если она ожидает третью, то выполняется третья. Это продолжается до тех пор, пока какая-нибудь корутина не ожидает объект Future. Объект Future фактически возвращает значение, и тогда цикл событий (event loop) получает управление.
Какое значение возвращает Future? Оно возвращает сам себя. Можете ли вы напрямую использовать yield для Future? Нет, это внутренняя деталь, о которой вам обычно не нужно беспокоиться.
class Awaitable:
def __await__(self):
future = asyncio.Future()
yield future
# RuntimeError: yield was used
# instead of yield from in task
async def coroutine():
await Awaitable()
loop = asyncio.get_event_loop()
loop.run_until_complete(coroutine())
Почему возникает эта ошибка? Как asyncio понимает, что это вы используете yield для Future, а не сам Future? Есть простая защита: Future устанавливает внутренний флаг перед тем, как вернуть управление.
👉@BookPython
with open('f') as f:
with open('g') as g:
with open('h') as h:
pass
Начиная с Python 2.7 и 3.1, это можно сделать с помощью одного выражения with:
o = open
with o('f') as f, o('g') as g, o('h') as h:
pass
До этого можно было использовать функцию contextlib.nested:
with nested(o('f'), o('g'), o('h')) as (f, g, h):
pass
Однако в современных версиях Python эта функция устарела и вызывает предупреждение. Вместо неё рекомендуется использовать более продвинутый инструмент — contextlib.ExitStack. Он позволяет войти в любое количество контекстов в произвольное время, но гарантирует их корректное завершение:
from contextlib import ExitStack
with ExitStack() as stack:
f = stack.enter_context(o('f'))
g = stack.enter_context(o('g'))
other = [
stack.enter_context(o(filename))
for filename in filenames
]
Это особенно полезно, когда количество контекстных менеджеров неизвестно заранее.
👉@BookPython
In : lion = 'Löwe'
In : lion.encode('utf-8')[2:]
Out: b'\xb6we'
In : lion.encode('utf-8')[2:].decode('utf-8')
...
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb6 in position 0: invalid start byte
Также это означает, что для пропуска первых N символов строки их необходимо прочитать и декодировать. Рассчитать смещение заранее невозможно.
Однако можно пропустить фиксированное количество байтов, принимая во внимание некоторые особенности. Вот как может быть закодирован символ в UTF-8:
0xxxxxxx
110xxxxx 10xxxxxx
1110xxxx 10xxxxxx 10xxxxxx
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
Как видно, байт является начальным байтом символа, если его вид не совпадает с 10xxxxxx. Такие байты называются продолжением символа (continuation bytes). Давайте пропустим их:
def cut_bytes(s, n):
result = s.encode('utf-8')[n:]
mask = int('11000000', 2)
conbyte = int('10000000', 2)
while result[0] and result[0] & mask == conbyte:
result = result[1:]
return result.decode('utf-8')
Пример использования:
In : cut_bytes(lion, 2)
Out: 'we'
In : cut_bytes(lion, 1)
Out: 'öwe'
👉@BookPythonos.path.join:
In : dir_path = '/home/vadim/'
In : file_name = 'test.py'
In : os.path.join(dir_path, file_name)
Out: '/home/vadim/test.py'
Это обычно лучше, чем использование строковой конкатенации:
In : dir_path + '/' + file_name
Out: '/home/vadim//test.py'
os.path.join использует правильный разделитель для текущей платформы (например, \ для Windows) и предотвращает появление двойного разделителя (//).
Начиная с Python 3.4, можно использовать класс Path из модуля pathlib. (С версии Python 3.6 его экземпляры также можно передавать в os.path.join.) Класс Path поддерживает объединение путей через оператор /:
In : Path('/home/vadim/') / Path('test.py')
Out: PosixPath('/home/vadim/test.py')
👉@BookPythonfloat в Python используют аппаратные возможности вашего компьютера, поэтому любое значение внутренне представлено в виде двоичной дроби.
Это означает, что в большинстве случаев вы работаете с приближениями, а не с точными значениями:
In : format(0.1, '.17f')
Out: '0.10000000000000001'
Модуль decimal позволяет использовать десятичную арифметику с произвольной точностью:
In : Decimal(1) / Decimal(3)
Out: Decimal('0.3333333333333333333333333333')
Однако и этого может быть недостаточно:
In [61]: Decimal(1) / Decimal(3) * Decimal(3) == Decimal(1)
Out[61]: False
Для точных вычислений можно использовать fractions, где любое число хранится в виде рационального:
In : Fraction(1) / Fraction(3) * Fraction(3) == Fraction(1)
Out: True
Очевидным ограничением остается то, что иррациональные числа (например, π) все равно будут представлены только в приближенной форме.
👉@BookPythontempfile.
Так как временные файлы обычно нужно удалять после использования, tempfile предоставляет как контекстный менеджер, так и простые функции:
import os
import tempfile
with tempfile.TemporaryDirectory() as dir_path:
open(os.path.join(dir_path, 'a'), 'w').close()
open(os.path.join(dir_path, 'b'), 'w').close()
open(os.path.join(dir_path, 'c'), 'w').close()
assert files_of(dir_path) == ['a', 'b', 'c']
👉@BookPython
Endi mavjud! Telegram Tadqiqoti 2025 — yilning asosiy insaytlari 
