Это четвёртая подборка советов про Python и программирование из моего авторского канала @pythonetc. Предыдущие подборки: Существует две концепции, которые легко спутать: переопределение (overriding) и перегрузка (overloading). Переопределение случается, когда дочерний класс определяет метод, уже предоставленный родительскими классами, и тем самым заменяет его. В каких-то языках требуется явным образом помечать переопределяющий метод (в C# применяется модификатор override), а в каких-то языках это делается по желанию (аннотация @Override в Java). Python не требует применять специальный модификатор и не предусматривает стандартной пометки таких методов (кто-то ради читабельности использует кастомный декоратор @override, который ничего не делает). С перегрузкой другая история. Этим термином обозначается ситуация, когда есть несколько функций с одинаковым именем, но с разными сигнатурами. Перегрузка возможна в Java и C++, она часто используется для предоставления аргументов по умолчанию: Python не поддерживает поиск функций по сигнатуре, только по имени. Конечно, вы можете написать код, явным образом анализирующий типы и количество аргументов, но это будет выглядеть неуклюже, и такой практики лучше избегать: Если вам нужны type hints, воспользуйтесь модулем typing с декоратором @overload: collections.defaultdict позволяет создать словарь, который возвращает значение по умолчанию, если запрошенный ключ отсутствует (вместо выбрасывания KeyError). Для создания defaultdictвам нужно предоставить не просто дефолтное значение, а фабрику таких значений. Так вы можете создать словарь с виртуально бесконечным количеством вложенных словарей, что позволит использовать конструкции вроде d[a][b][c]...[z]. Такое поведение называется «автовивификацией», этот термин пришёл из Perl. Инстанцирование объектов включает в себя два важных шага. Сначала из класса вызывается метод __new__, который создаёт и возвращает новый объект. Затем из него Python вызывает метод __init__, который задаёт начальное состояние этого объекта. Однако __init__ не будет вызван, если __new__ возвращает объект, не являющийся экземпляром исходного класса. В этом случае объект мог быть создан другим классом, и значит __init__ уже вызывался на объекте: Это также означает, что не следует создавать экземпляры того же класса в __new__ с помощью обычного конструктора (Foo(...)). Это может привести к повторному исполнению __init__, или даже к бесконечной рекурсии. Бесконечная рекурсия: Двойное исполнение __init__: Правильный способ: В Python можно переопределить оператор , определив магический метод __getitem__. Так, например, можно создать объект, который виртуально содержит бесконечное количество повторяющихся элементов: Необычное здесь заключается в том, что оператор  поддерживает уникальный синтаксис. С его помощью можно получить не только , но и , ,  и даже . Семантика оператора такая: [start:stop:step], однако вы можете использовать его любым иным образом для создания кастомных объектов. Но если вызывать с помощью этого синтаксиса __getitem__, что он получит в качестве индексного параметра? Именно для этого существуют slice-объекты. Можно даже объединить синтаксисы кортежей и слайсов: slice ничего не делает, только хранит атрибуты start, stop и step. Любую исполняемую корутину (coroutine) asyncio можно прервать с помощью метода cancel(). При этом в корутину будет отправлена CancelledError, в результате эта и все связанные с ней корутины будут прерваны, пока ошибка не будет поймана и подавлена. CancelledError — подкласс Exception, а значит её можно случайно поймать с помощью комбинации try ... except Exception, предназначенной для ловли «любых ошибок». Чтобы безопасно для сопрограммы поймать ошибку, придётся делать так: Для планирования исполнения какого-то кода в определённое время в asyncio обычно создают task, которая выполняет await asyncio.sleep(x): Но создание новоого таска может стоить дорого, да это и не обязательно делать, если вы не планируете выполнять асинхронные операции (вроде функции do в моём примере). Вместо этого можно использовать функции loop.call_later и loop.call_at, которые позволяют запланировать вызов асинхронного коллбека: