Библиотека Python разработчика | Книги по питону
Погружение в CPython и архитектуру. Разбираем неочевидное поведение (GIL, Memory), Best Practices (SOLID, DDD) и тонкости Django/FastAPI. Решаем задачи с подвохом и оптимизируем алгоритмы. 🐍 По всем вопросам @evgenycarter РКН clck.ru/3Ko7Hq
Показати більше📈 Аналітичний огляд Telegram-каналу Библиотека Python разработчика | Книги по питону
Канал Библиотека Python разработчика | Книги по питону (@bookpython) у мовному сегменті Російська є активним учасником. На даний момент спільнота об'єднує 17 959 підписників, посідаючи 7 250 місце в категорії Технології та додатки та 36 565 місце у регіоні Росія.
📊 Показники аудиторії та динаміка
З моменту свого створення невідомо, проект продемонстрував стрімке зростання, зібравши аудиторію у 17 959 підписників.
За останніми даними від 04 листопада, 2026, канал демонструє стабільну активність. Хоча за останні 30 днів спостерігається зміна кількості учасників на -87, а за останні 24 години на -3, загальне охоплення залишається високим.
- Статус верифікації: Не верифікований
- Рівень залученості (ER): Середній показник залученості аудиторії становить 5.31%. Протягом перших 24 годин після публікації контент зазвичай збирає 2.70% реакцій від загальної кількості підписників.
- Охоплення публікацій: В середньому кожен допис отримує 953 переглядів. Протягом першої доби публікація в середньому набирає 485 переглядів.
- Реакції та взаємодія: Аудиторія активно підтримує контент: середня кількість реакцій на один пост – 4.
- Тематичні інтереси: Контент зосереджений навколо ключових тем, таких як numbers, yield, модуль, none, декоратор.
📝 Опис та контентна політика
Автор описує ресурс як майданчик для висловлення суб'єктивної думки:
“Погружение в CPython и архитектуру. Разбираем неочевидное поведение (GIL, Memory), Best Practices (SOLID, DDD) и тонкости Django/FastAPI. Решаем задачи с подвохом и оптимизируем алгоритмы. 🐍
По всем вопросам @evgenycarter
РКН clck.ru/3Ko7Hq”
Завдяки високій частоті оновлень (останні дані отримано 05 листопада, 2026), канал підтримує актуальність та високий рівень охоплення публікацій. Аналітика показує, що аудиторія активно взаємодіє з контентом, що робить його важливою точкою впливу в категорії Технології та додатки.
ö can be just LATIN SMALL LETTER O WITH DIAERESIS (U+00F6) or a combination of o and a diaeresis modifier: LATIN SMALL LETTER O (U+006F) + COMBINING DIAERESIS (U+0308).
Compatible sequences look different but may be treated the same semantically, e. g. ff and ff.
For each of these types of equivalence, you can normalize a Unicode string by compressing or decompressing sequences. In Python, you can use unicodedata for this:
modes = [
# Compress canonically equivalent
'NFC',
# Decompress canonically equivalent
'NFD',
# Compress compatible
'NFKC',
# Decompress compatible
'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__init__ it may be better to pass them as arguments and have a factory method instead. It separates business logic from technical details on how objects are created.
In this example __init__ accepts host and port to construct a database connection:
class Query:
def __init__(self, host, port):
self._connection = Connection(host, port)
The possible refactoring is:
class Query:
def __init__(self, connection):
self._connection = connection
@classmethod
def create(cls, host, port):
return cls(Connection(host, port))
This approach has at least these advantages:
• It makes dependency injection easy. You can do Query(FakeConnection()) in your tests.
• The class can have as many factory methods as needed; the connection may be constructed not only by host and port but also by cloning another connection, reading a config file or object, using the default, etc.
• Such factory methods can be turned into asynchronous functions; this is completely impossible for __init__.utf-8, which is (usually) a default in Python. When you read from a file, Python automatically decodes utf-8. You can choose any other encoding with encoding= parameter of the open function, or you can read plane bytes by appending b to its mode.obj.x = y you can't be sure that the attributed of obj named x is now equal to y. Python descriptor protocol lets define how attribute assignment is handled.
class Descriptor:
def __set__(self, obj, value):
obj.test = value
class A:
x = Descriptor()
In this example, x is never assigned, but the test attribute is assigned instead:
In : a = A()
In : a.x = 42
In : a.test
Out: 42
In : a.x
Out: <__main__.Descriptor at 0x7ff7baef51d0>
In case you actually need to change the x attribute as a part of tests or advanced metaprogramming, you have to modify __dict__ directly:
In : a.__dict__['x'] = 42
In : a.x
Out: 42Ellipsis which is also can be written as .... This constant has no special meaning for the interpreter but is used in places where such syntax looks appropriate.
numpy support Ellipsis as a __getitem__ argument, e. g. x[...] returns all elements of x.
PEP 484 defines additional meaning: Callable[..., type] is a way to define a type of callables with no argument types specified.
Finally, you can use to indicate that function is not yet implemented. This is a completely valid Python code:
def x():
...asyncio, if coroutine raises an exception, it's then propagated to the code that awaits the corresponding future. If multiple places do await, every one of them gets the exception (since it's stored in the exception). The following code prints error five times:
import asyncio
async def error():
await asyncio.sleep(1)
raise ValueError()
async def waiter(task):
try:
await task
except ValueError:
print('error')
else:
print('OK')
async def main():
task = asyncio.get_event_loop().create_task(error())
for _ in range(5):
asyncio.get_event_loop().create_task(waiter(task))
await asyncio.sleep(2)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
If an exception is raised, but the task is never awaited, the exception is lost. In that case, when the task is destroyed, it warns you with “Task exception was never retrieved” message.
When you use await asyncio.gather(tasks) and one of the tasks raises an exception, it is propagated to you. However, if multiple tasks raise exceptions, you still only get the first one, the others are silently lost:
import asyncio
async def error(i):
await asyncio.sleep(1)
raise ValueError(i)
async def main():
try:
await asyncio.gather(
error(1),
error(2),
error(3),
)
except ValueError as e:
print(e)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
You may use gather with return_exceptions=True that make it return exceptions as though they are regular result values. The following code prints [42, ValueError(2,), ValueError(3,)]:
import asyncio
async def error(i):
await asyncio.sleep(1)
if i > 1:
raise ValueError(i)
return 42
async def main():
results = await asyncio.gather(
error(1),
error(2),
error(3),
return_exceptions=True,
)
print(results)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())