11.01 Объектная модель Python
Превращение функции-атрибута класса в метод объекта при инстанциировании (пример из лекции)
реализуйте класс Rectangle для прямоугольника, стороны которого параллельны координатным осям. В классе должны быть:
поля x1, y1, x2, y2, хранящие координаты "левой нижней" и "правой верхней" вершин (т.е. x1<x2, y1<y2; проверять эти условия при инициализации не требуется)
метод __init__(), в который передаются значения x1, y1, x2, y2
метод __str__(), формирующий строку с координатами четырех вершин прямоугольника, т.е. строку вида "(x1,y1)(x1,y2)(x2,y2)(x2,y1)"
класс пригодится для остальных упражнений
Поля класса vs поля объекта (видимость) — пример из лекции
в классе Rectangle создайте поле rectcnt (счетчик объектов этого класса, первоначально 0); добавьте в метод __init__() увеличение этого поля на 1, проверьте, что после создания N объектов оно равно N
Подсказка — надо ходить либо к полю класса непосредственно, либо сделать rectcnt списком из одного элемента, и менять этот элемент
Использование setattr() / getattr() / .__dict__
Добавьте в метод __init__() создание поля rect_<k>, где k - номер объекта Rectangle в нумерации с 1. Создайте несколько объектов Rectangle; проверьте при помощи dir(<объект>), что в каждом из объектов есть поле rect_<k> с соответствующим значением k.
поле создавайте через setattr(); желающие могут попробовать напрямую модифицировать self.__dict__
в классе Rectangle создайте методы для операций сравнения "<" (__lt__()) и "==" (__eq__()); эти операции должны сравнивать числа - площади прямоугольников.
в классе Rectangle создайте методы для операций умножения на число. Операция должна возвращать объект Rectangle, все координаты вершин которого умножены на это число. Реализуйте:
"обычное" умножение, вида myrect * 5 (через __mul__())
"правое" умножение, вида 5 * myrect (через __rmul__())
в классе Rectangle создайте метод для операции доступа по индексу (__getitem__()). По индексам от 0 до 3 должны возвращаться кортежи-координаты вершин, соответственно, (x1,y1); (x1,y2); (x2,y2); (x2,y1).
Согласно протоколу итерации, такой объект должен получиться итерируемым (с исключением IndexError в качестве конца итерации). Проверьте это: превратите прямоугольник в список или выведите координаты вершин в цикле.
Д/З
Написать класс Omnibus
экземпляры которого (обозначим экземпляр omn) обладают следующими свойствами
Для любого атрибута (если его имя не начинается на "_", такие имена не входят в тесты) можно написать операцию omn.атрибут = значение (значение не хранится и не используется, см. далее)
После этого выражение omn.атрибут будет возвращать количество экземпляров класса, для которых было таким способом задано поле атрибут
Операция del omn.атрибут отменяет действие пункта 1 (поле атрибут считается не заданным для данного объекта, у других объектов оно уменьшается на 1).
- Если соответствующего атрибута у объекта нет, ничего не происходит.
Input
1 a, b, c = Omnibus(), Omnibus(), Omnibus() 2 del a.random 3 a.i = a.j = a.k = True 4 b.j = b.k = b.n = False 5 c.k = c.n = c.m = hex 6 print(a.i, a.j, a.k, b.j, b.k, b.n, c.k, c.n, c.m) 7 del a.k, b.n, c.m 8 print(a.i, a.j, b.j, b.k, c.k, c.n) 9 del a.k, c.m 10 print(a.i, a.j, b.j, b.k, c.k, c.n) 11 a.k = b.i = c.m = 777 12 print(a.i, a.j, a.k, b.j, b.k, c.k, c.n, c.m)
Output
1 2 3 2 3 2 3 2 1 1 2 2 2 2 1 1 2 2 2 2 1 2 2 3 2 3 3 1 1
- В каждом из собственных тестов надо проверять все три свойства этого класса
Написать класс Triangle, треугольника на плоскости,
- в котором будут:
Конструктор по трём точкам на плоскости (три последовательности неотрицательных чисел из двух элементов каждая, не забыть преобразовать их в tuple или list)
Площадь треугольника: abs(треугольник), равна нулю, если треугольник невозможен (реализуется с помощью .__abs__())
Треугольник с нулевой площадью — пустой (реализуется с помощью метода .__bool__())
Сравнение треугольников на "<" — это сравнение площадей
Булевская операция треугольник1 in треугольник2 — проверка того, что один треугольник целиком содержится во втором (в частности, треугольник содержится сам в себе, а пустой треугольник содержится в любом)
Булевская операция треугольник1 & треугольник2 — проверка того, что два треугольника пересекаются (треугольник с нулевой площадью не имеет точек и ни с чем не пересекается)
Input
1 r = Triangle((4, 2), (1, 3), (2, 4)) 2 s = Triangle((1, 1), (3, 1), (2, 2)) 3 t = Triangle((0, 0), (2, 3), (4, 0)) 4 o = Triangle((1, 1), (2, 2), (3, 3)) 5 print(*(f"{n}({bool(x)}):{round(abs(x), 3)}" for n, x in zip("rsto", (r, s, t, o)))) 6 print(f"{s < t=}, {o < t=}, {r < t=}, {r < s=}") 7 print(f"{s in t=}, {o in t=}, {r in t=}") 8 print(f"{r & t=}, {t & r=}, {s & r=}, {o & t=}")
Output
r(True):2.0 s(True):1.0 t(True):6.0 o(False):0 s < t=True, o < t=True, r < t=True, r < s=False s in t=True, o in t=True, r in t=False r & t=True, t & r=True, s & r=False, o & t=False
- В каждом из собственных тестов надо проверять все шесть свойств треугольника. Координаты в тестах предполагаются целочисленными. Точность вещественных чисел (например, площади) при выводе ограничивать до трёх знаков после запятой, как в примере.
- в котором будут:
Написать класс Grange, реализующий отрезок целочисленной геометрической прогрессии ( по аналогии с range(), но есть и отличия) $$ b_n=b_0*q^n $$.
- В классе должны быть:
Конструктор по трём параметрам (b0 , q и граница, за которую не заходит bn)
Длина отрезка len(прогрессия)
Прогрессия с нулевой длиной отрезка должна быть пустой
Индексирование прогрессия[i] = bi ; индекс может быть любым неотрицательным целым (граница отрезка не проверяется)
Итератор iter(прогрессия) (все элементы отрезка)
Секционирование вида прогрессия[начало:конец] должно давать новую прогрессию с тем же q
Секционирование вида прогрессия[начало:конец:знаменатель] должно давать новую прогрессию с qзнаменатель
- Будем считать, что знаменатель только натуральный, проверять не надо
Оба метода .__str__() и __repr__() должны возвращать grange(b₀, q, bmax)
Input
1 f, g, h = Grange(1, 2, 1048575), Grange(1, 2, 1048576), Grange(1, 2, 1048577) 2 o, e = Grange(1, 2, 1), Grange(100, 10, 200) 3 print(f"{f=}, {g=}, {h=}") 4 print(f"{list(o)}({not(o)}), {list(e)}({not(e)})") 5 print(f"{len(f)=}, {len(g)=}, {len(h)=}") 6 print(f"{len(list(f))=}, {len(list(g))=}, {len(list(h))=}") 7 print(f"{f[0]=}, {h[24]=}") 8 a, b = f[3:32767], h[3:32767:2] 9 print(f"{a=}, {a[5]=}") 10 print(f"{b=}, {b[5]=}, {list(b)=}")
Output
f=grange(1, 2, 1048575), g=grange(1, 2, 1048576), h=grange(1, 2, 1048577) [](True), [100](False) len(f)=20, len(g)=20, len(h)=21 len(list(f))=20, len(list(g))=20, len(list(h))=21 f[0]=1, h[24]=16777216 a=grange(3, 2, 32767), a[5]=96 b=grange(3, 4, 32767), b[5]=3072, list(b)=[3, 12, 48, 192, 768, 3072, 12288
- В каждом из собственных тестов надо проверять все восемь свойств прогрессии
- В классе должны быть: