Библиотека Python разработчика | Книги по питону
Погружение в CPython и архитектуру. Разбираем неочевидное поведение (GIL, Memory), Best Practices (SOLID, DDD) и тонкости Django/FastAPI. Решаем задачи с подвохом и оптимизируем алгоритмы. 🐍 По всем вопросам @evgenycarter РКН clck.ru/3Ko7Hq
Показати більше📈 Аналітичний огляд Telegram-каналу Библиотека Python разработчика | Книги по питону
Канал Библиотека Python разработчика | Книги по питону (@bookpython) у мовному сегменті Російська є активним учасником. На даний момент спільнота об'єднує 17 967 підписників, посідаючи 7 269 місце в категорії Технології та додатки та 36 632 місце у регіоні Росія.
📊 Показники аудиторії та динаміка
З моменту свого створення невідомо, проект продемонстрував стрімке зростання, зібравши аудиторію у 17 967 підписників.
За останніми даними від 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), канал підтримує актуальність та високий рівень охоплення публікацій. Аналітика показує, що аудиторія активно взаємодіє з контентом, що робить його важливою точкою впливу в категорії Технології та додатки.
__hash__. Этот метод может возвращать любое целое число, но есть одно обязательное условие: равные объекты должны иметь одинаковые хэши (обратное не обязательно).
Также не стоит использовать изменяемые объекты в качестве ключей, потому что если объект изменится и станет не равным самому себе в прошлом, его больше нельзя будет найти в словаре.
Есть и один странный момент, который может удивить во время отладки или написания unit-тестов:
class A:
def __init__(self, x):
self.x = x
def __hash__(self):
return self.x
hash(A(2)) # 2
hash(A(1)) # 1
hash(A(0)) # 0
hash(A(-1)) # внимание!
# -2
hash(A(-2)) # -2
В CPython значение -1 зарезервировано для внутренних ошибок, поэтому оно неявно преобразуется в -2.
👉@BookPythoncollections предоставляет класс ChainMap, который позволяет использовать несколько отображений (словарей) как одно объединённое:
from collections import ChainMap
d = ChainMap(dict(a=1), dict(a=2, b=2))
d['a'] # 1
d['b'] # 2
d['c'] # ...
# KeyError: 'c'
ChainMap последовательно просматривает все вложенные отображения и возвращает первое найденное значение. Однако все операции изменения затрагивают только первое отображение:
d = ChainMap(dict(a=1), dict(a=2, b=2))
d['c'] = 3
d
# ChainMap({'a': 1, 'c': 3}, {'a': 2, 'b': 2})
👉@BookPython
a = [2, -1, 0, 1, -2]
sorted(a, key=lambda x: x**2)
# [0, -1, 1, 2, -2]
Функции max и min тоже стараются быть согласованными с поведением sorted.
max работает аналогично sorted(a, reverse=True)[0], а min — как sorted(a)[0].
Это означает, что обе функции возвращают самый левый возможный результат:
max([2, -2], key=lambda x: x**2)
# 2
max([-2, 2], key=lambda x: x**2)
# -2
min([2, -2], key=lambda x: x**2)
# 2
min([-2, 2], key=lambda x: x**2)
# -2
👉@BookPython__repr__ и прочие подобные вещи:
class Server:
def __init__(self, ip, version=4):
self.ip = ip
self._version = version
def __repr__(self):
return '{klass}("{ip!r}", {version!r})'.format(
klass=type(self).__name__,
ip=self.ip,
version=self._version,
)
Один из способов упростить такую рутину — использовать популярный пакет attrs, который автоматически генерирует множество стандартных методов на основе нескольких деклараций:
class Server:
ip = attrib()
_version = attrib(default=4)
server = Server(ip='192.168.0.0.1', version=4)
Этот подход не только создаёт конструктор (__init__) и представление (__repr__), но и полный набор методов сравнения (__eq__, __lt__ и т. д.).
Кроме того, в Python 3.7 появилась стандартная альтернатива — data classes (датаклассы), которые решают ту же задачу (и даже больше). Они используют аннотации переменных — ещё одну относительно новую функцию Python. Вот пример:
@dataclass
class InventoryItem:
name: str
unit_price: float
quantity_on_hand: int = 0
def total_cost(self) -> float:
return self.unit_price * self.quantity_on_hand
Таким образом, dataclass тоже автоматически создаёт __init__, __repr__, методы сравнения и многое другое, основываясь лишь на аннотациях типов.for и инструкции with.
Все эти примеры некорректны:
name: str, age: int = student
for x: int in numbers:
...
with connection() as conn: Connection:
...
Правильный способ указать тип таких переменных — объявить их заранее, без инициализации:
conn: Connection
with connection() as conn:
...
👉@BookPython-h или --help), опций с параметрами (--log-level 2) или позиционных параметров (cp file1 file2).
Опции отличаются от позиционных параметров тем, что начинаются с одного или двух дефисов. Проблемы возникают, когда позиционные аргументы тоже начинаются с дефиса — например, если нужно удалить файл с именем -rf: команда rm -rf в таком случае не работает как ожидается.
Общепринятый способ решения этой проблемы — поддержка разделителя --. Аргументы, идущие после --, никогда не интерпретируются как опции:
$ echo test > -rf
$ cat -rf
cat: invalid option -- 'r'
Try 'cat --help' for more information.
$ cat -- -rf
test
$ rm -- -rf
$ cat -- -rf
cat: -rf: No such file or directory
Модуль argparse автоматически обрабатывает -- за тебя.
👉@BookPython
try:
cache
except NameError:
cache = {}
На первый взгляд, в этом нет смысла: cache однозначно вызовет NameError в начале модуля, так как переменной ранее не присваивалось значение.
Однако это не так, если модуль перезагружается. В этом случае словарь, содержащий все атрибуты модуля, повторно используется, что даёт модулю возможность повторно использовать атрибуты своего предыдущего экземпляра. Если модуль спроектирован с учётом возможности перезагрузки, он может опираться на эту особенность. Например, приведённый выше код сохранить кэш при перезагрузке модуля.
👉@BookPythonsys.modules:
In : import sys
In : 'sys' in sys.modules.keys()
Out: True
Если вам действительно нужно перезагрузить модуль, следует использовать функцию importlib.reload(m). Здесь m — это объект модуля, который был успешно импортирован ранее, а не строка с его именем:
In : import importlib
In : importlib.reload(importlib)
Out[5]: <module 'importlib' from '/home/bookpython/.ve/pythonetc/lib/python3.6/importlib/__init__.py'>
👉@BookPython
>>> 2 + 2
4
>>> _
4
Во-вторых, в документации модуля gettext рекомендуется создавать псевдоним для функции gettext() в виде _(), чтобы не загромождать код.
В-третьих, _ используется, когда необходимо придумать имя для значения, которое не представляет интереса:
>>> log_entry = '10:50:24 14234 GET /api/v1/test'
>>> time, _, method, location = log_entry.split()
👉@BookPythonexcept Exception, а не голый except:
try:
foreign()
except Exception:
logging.warn('fail', exc_info=True)
Голый except эквивалентен except BaseException. А разница между BaseException и Exception в том, что BaseException включает исключения, которые, как правило, ловить не следует, например, KeyboardInterrupt.
👉@BookPython[] можно переопределить, реализовав магический метод __getitem__. Это позволяет, например, создать объект, который виртуально содержит бесконечное количество повторяющихся элементов:
class Cycle:
def __init__(self, lst):
self._lst = lst
def __getitem__(self, index):
return self._lst[index % len(self._lst)]
print(Cycle(['a', 'b', 'c'])[100]) # 'b'
Необычность оператора [] в Python в том, что он поддерживает особый синтаксис. Его можно использовать не только так: [2], но и так: [2:10], [2:10:2], [2::2] или даже [:]. Смысл такой записи — [start:stop:step], но в ваших собственных объектах вы можете использовать этот синтаксис как угодно.
Что же передаётся в __getitem__ в таких случаях? Объекты slice созданы специально для этого.
Пример:
class Inspector:
def __getitem__(self, index):
print(index)
Inspector()[1]
# 1
Inspector()[1:2]
# slice(1, 2, None)
Inspector()[1:2:3]
# slice(1, 2, 3)
Inspector()[:]
# slice(None, None, None)
Inspector()[:, 0, :]
# (slice(None, None, None), 0, slice(None, None, None))
Объект slice сам по себе ничего не делает — он просто хранит атрибуты start, stop и step:
s = slice(1, 2, 3)
print(s.start) # 1
print(s.stop) # 2
print(s.step) # 3
👉@BookPython