11.10 Наследование и исключения
Наследование
Видимость полей в цепочке наследования
Задать класс A с полем A.v = 1, класс B(A) с полем B.v = 2 и объект b = B() с полем b.v = 3. Посмотреть, чему будет равно b.v до и после удаления .v сначала из объекта b, а затем из класса B.
Проблема порождения нового объекта (например, суммы) базового класса при выполнении унаследованной операции над объектами производного класса
Пофиксить проблему с помощью self.__class__ на примере из демонстрации
Использование type(Имя, предки, словарь_полей) для создания базового и дочернего классов; в т. ч. пример имени поля не-идентификатора (например, «Q-Q!»).
Приделать к такому классу __init__ и __str__, которые будут задавать и превращать в строку значение такого поля
Защита от коллизии имён .__Имя → ._Класс__Имя
Проверить, как работает этот эффект при создании класса с помощью type(Имя, предки, словарь_полей) (спойлер:
super()
Например, дёрнуть «родительский» __init__()
Линейно унаследовать A → B → C, так, чтобы объект.__str__() выводил путь по дереву наследования, например "A:B" для print(B())
Исключения
Иерархия исключений: пример из лекции
Программа, которая заставляет человека вводить что-либо до тех пор, пока он не введёт целое число (int(input())) TODO: падаванка и упражненька про with (который появится в обновлённой лекции)
в 2025 году with на лекции не было ☹
- Исключение — это не «ошибка», а нелинейная передача управления
Написать две функции itemget(collection, index), которая просто возвращает collection[index], и safeindex(function, *args), которая возвращает результат function с параметрами args, а при возникновении исключения IndexError — None. Проверить работоспособность (например, так: list(safeindex(itemget, "qwe", i) for i in range(5)) — или любым более простым путём ☺)
Проверить, что исключение TypeError (например, safeindex(itemget, "qwe", "qwe")) не перехватывается
Вброс исключений — raise
Написать функцию div(a, b, eps), которая вбрасывает ZeroDivisionError, если знаменатель по модулю меньше eps
StephenMalchevskii: если успеем — управление контекстом исключений
__context__ и __cause__, Exception Chaining с помощью raise from
Написать функцию safesafeindex(collection, *args), представляющую любое исключение в виде IndexError, однако цепочкой передавать правильное исключение и в случае «не настоящего» исключения выводить NotANone: <Real Exception>: Принципиально в этом упражнении сделать вложенные исключения!
Вложенную часть можно вынести в виде отдельной функции, тогда любое исключение в ней должно «заворачиваться» в IndexError; в самой функции тогда должна быть обработка только IndexError
Проверить, что safesafeindex(itemget, "qwe", "qwe") работает (а ещё вот такое: safeindex(eval, "1/0") ☺)
Граф множественного наследования и MRO
Пример невалидного наследования class A: pass class B(A): pass class Y(B, A): pass class X(A, B): pass
- Заданы 4 класса:
class A: pass class B: pass class C(A, B): pass class D(B, A): pass
Сколькими способами можно унаследовать класс E от двух классов, один из которых (необязательно первый) — C?
Написать программу, которая пробует все варианты, и подсчитывает, сколько раз не было исключений
Д/З
Дистанционные тесты. TODO Ждём результатов от студентов старших курсов
Задача_1: Написать класс DivStr (унаследованный от collections.UserString), в котором:
Добавлена возможность заведения пустой строки без параметров — DivStr()
Добавлена операция a // n — возвращается итератор из n подстрок одинакового наибольшего размера, на которые можно разбить исходную строку
Добавлена операция a % n — возвращается «остаток от деления», хвостик, который надо приписать к a // n, чтобы получилась вся строка (возможно, пустой)
Input
Output
XcDf QWEa sdER Tdfg RTY ERT dfg RTY y cD fQ WE gRTYY
Задача_2: Написать программу, которая заставляет человека вводить координаты вершин треугольника в формате (x1, y1), (x2, y2), (x3, y3), до тех пор, пока это не окажутся координаты вершин треугольника в указанном формате, а потом выводит его площадь с точностью до сотой.
Если формат ввода неправильный, программа вместо площади выводит «Invalid input», а если формат условно правильный, но площадь его нулевая или вычислить её нельзя, потому что введены вообще не числа — «Not a triangle».
Диагностика ввода и расчет площади производится в функции triangleSquare, которая:
- получает на вход входную строку программы
преобразует строку в координаты вершин: (x1, y1), (x2, y2), (x3, y3) = eval(inStr)
при преобразовании ловит все исключения, и при любом перехваченном исключении формирует исключение InvalidInput (этот класс нужно определить)
если ввод корректен, выполняет проверку на то, что координаты - корректны для треугольника; в случае некорректности формирует исключение BadTriangle (этот класс нужно определить)
- если координаты корректны, то вычисляет и возвращает площадь
При вызове функции triangleSquare в основном коде программы ловятся исключения InvalidInput и BadTriangle, и в блоках их обработки выдается соответствующая диагностика
Вывод площади выполняется в блоке else
- Написать тесты:
- на неправильный формат
- на не-треугольник
Input:
asdf 1,2,3,4,5,6 (1,1), (2,2), (11,11) (1,2), (4,5), (9,8)
Output:
Invalid input Invalid input Not a triangle 3.00
Задача_3 на иерархию исключений - Написать программу, в которой есть:
Несложная иерархия исключений: базовый класс Undead и наследники Skeleton, Zombie и Ghoul
Функция necro(a), которая в зависимости от остатка от деления a на 3 формирует исключение: 0 - Skeleton, 1 - Zombie, 2 - Ghoul
Ввод целочисленных значений x и y
Цикл по range(x,y), в теле цикла: вызов necro(), перехват исключений следующих типов (и в таком порядке): Skeleton, Zombie, Undead; при обработке исключений вывод текста, соответственно, "Skeleton", "Zombie", "Generic Undead"
Input:
11, 17
Output:
Generic Undead Skeleton Zombie Generic Undead Skeleton Zombie
- Написать программу, в которой есть:
