F. Классный прямоугольник 2.0

Расширим функционал класса написанного вами в предыдущей задаче.

Реализуйте методы:

  • get_pos() — возвращает координаты верхнего левого угла в виде кортежа;
  • get_size() — возвращает размеры в виде кортежа;
  • move(dx, dy) — изменяет положение на заданные значения;
  • resize(width, height) — изменяет размер (положение верхнего левого угла остаётся неизменным).

Примечание

Ваше решение должно содержать только классы и функции.
В решении не должно быть вызовов инициализации требуемых классов.
Все результаты вычислений нужно округлить до сотых.

Пример

Ввод

rect = Rectangle((3.2, -4.3), (7.52, 3.14))
print(rect.get_pos(), rect.get_size())
rect.move(1.32, -5)
print(rect.get_pos(), rect.get_size())

Вывод

(3.2, 3.14) (4.32, 7.44)
(4.52, -1.86) (4.32, 7.44)

Ввод

rect = Rectangle((7.52, -4.3), (3.2, 3.14))
print(rect.get_pos(), rect.get_size())
rect.resize(23.5, 11.3)
print(rect.get_pos(), rect.get_size())

Вывод

(3.2, 3.14) (4.32, 7.44)
(3.2, 3.14) (23.5, 11.3)

Решение

Очень хорошее развитие предыдущей задачи. С одной стороны можно продолжать дорабатывать код из первой задачи, а с другой стороны можно заметить, Что нас подталкивают к тому, чтобы перейти от описания прямоугольника в виде пары координат к описанию “левый верхний угол, высота, ширина”.

На это указывает условие реализации метода resize(). Напомню, что там предлагают, чтобы левая верхняя точка оставалась в неизменном положении.

Это, в самом деле , более удобный подход, в чем можно будет убедиться в следующем задании.

И хотя мы могли бы использовать метод move() класса Point(), мы не будем этого делать, потому что в этом нет большого смысла. В классе Point() метод move() перемещает точку в новые координаты, а нам требуется ее сместить относительно текущего положения. Все это приводит к тому, что мы так или иначе будем вынуждены вычислить новые координаты, но вместо вызова метода move() точки из метода move() нашего прямоугольника, будет проще модифицировать координаты угла напрямую. При этом надо отдавать себе отчет, что это не является хорошей практикой в ООП.

Хорошей практикой ООП было бы использование методов, считывающих и устанавливающих координаты точки, но, с другой стороны, так как вызов функции – одна из самых дорогих операций в python, при больших объемах вычислений, этой практикой можно пренебречь.

Посмотреть код

Решение

Python
# продолжение первого, наивного решения

class Rectangle:
    def __init__(self, corner1, corner2) -> None:
        self.left_down = [min(corner1[0], corner2[0]),
                          min(corner1[1], corner2[1])]
        self.up_right = [max(corner1[0], corner2[0]),
                         max(corner1[1], corner2[1])]

    def perimeter(self):
        return round((self.up_right[0] - self.left_down[0]) * 2 +
                     (self.up_right[1] - self.left_down[1]) * 2, 2)

    def area(self):
        return round((self.up_right[0] - self.left_down[0]) *
                     (self.up_right[1] - self.left_down[1]), 2)

    def get_pos(self):
        return round(self.left_down[0], 2), round(self.up_right[1], 2)

    def get_size(self):
        return round(self.up_right[0] - self.left_down[0], 2), \
            round(self.up_right[1] - self.left_down[1], 2)

    def move(self, dx, dy):
        self.left_down[0] += dx
        self.left_down[1] += dy
        self.up_right[0] += dx
        self.up_right[1] += dy

    def resize(self, width, height):
        self.up_right[0] = self.left_down[0] + width
        self.left_down[1] = self.up_right[1] - height

Решение

Python
# решение на основе класса Point

class Point:
    def __init__(self, x, y) -> None:
        self.x = x
        self.y = y
        self.round()

    def round(self):
        self.x = round(self.x, 2)
        self.y = round(self.y, 2)
        return self


class Rectangle:
    def __init__(self, corner1, corner2) -> None:
        self.corner = Point(min(corner1[0], corner2[0]), max(corner1[1], corner2[1]))  # noqa
        self.width = round(max(corner1[0], corner2[0]) - self.corner.x, 2)
        self.height = round(self.corner.y - min(corner1[1], corner2[1]), 2)

    def perimeter(self):
        return round((self.width + self.height) * 2, 2)

    def area(self):
        return round(self.width * self.height, 2)

    def get_pos(self):
        return self.corner.x, self.corner.y

    def get_size(self):
        return self.width, self.height

    def move(self, dx, dy):
        self.corner.x += dx
        self.corner.y += dy
        self.corner.round()

    def resize(self, width, height):
        self.width = round(width, 2)
        self.height = round(height, 2)
Подписаться
Уведомить о
guest
16 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
Расул
Расул
05.08.2024 15:21

class Rectangle:

def __init__(self, tuple1, tuple2):
self.x1 = tuple1[0]
self.y1 = tuple1[1]
self.x2 = tuple2[0]
self.y2 = tuple2[1]
self.widt = round((abs(self.x2 – self.x1)), 2)
self.heiht = round((abs(self.y1 – self.y2)), 2)

def perimeter(self):
return round((2 * (abs(self.x2 – self.x1)) + 2 * (abs(self.y2 – self.y1))), 2)

def area(self):
return round((abs(self.x2 – self.x1) * abs(self.y2 – self.y1)), 2)

def get_pos(self):
a = (round(min(self.x1, self.x2), 2), round((max(self.y1, self.y2)), 2))
return a

def get_size(self):
b = (round(self.widt, 2), round(self.heiht, 2))
return b

def move(self, dx, dy):
self.x1 += dx
self.x2 += dx
self.y1 += dy
self.y2 += dy

def resize(self, width, height):
self.widt = round(width, 2)
self.heiht = round(height, 2)
может подскажет кто, что не так в этом решении, проходит только первые два теста

Степан
14.08.2024 17:49

Не очень понимаю, почему в задаче в методе resize() нельзя просто назначать новые width и height, а потом их же и выводить? Положение верхнего левого угла остается неизменным, так какая разница какие там координаты у других углов?

Но из-за этого у меня явно не проходит проверку код

class Rectangle:

def __init__(self, corner_1: tuple, corner_2: tuple):
self.corner_1 = corner_1
self.corner_2 = corner_2
self.left_x = min(self.corner_1[0], self.corner_2[0])
self.left_y = max(self.corner_1[1], self.corner_2[1])
self.width = abs(self.corner_2[0] – self.corner_1[0])
self.length = abs(self.corner_2[1] – self.corner_1[1])

def get_size(self):
return tuple((round(self.width, 2), round(self.length, 2)))

def move(self, dx, dy):
self.left_x += dx
self.left_y += dy

def get_pos(self):
return tuple((round(self.left_x, 2), round(self.left_y, 2)))

def resize(self, width, height):
self.width = width
self.length = height

Степан
Ответить на  Сергей Клочко
14.08.2024 18:06

Моя проблема оказалась в другом: это задание, наследуя предыдущее, также требует наличия методов perimeter и area. По каким-то причинам для меня это оказалось неочевидно, хотя в начале и написано, что нужно “дополнить” класс из предыдущего задания

Сергей, спасибо! Все так

Тимур
Тимур
01.11.2024 21:45

Всем привет!
Подскажите, пожалуйста, в чем может быть проблема? Отталкивался от изменения координат точек. Первые два теста проходит, но на третьем ошибка исполнения (RE)

class Rectangle():

  def __init__(self, point_1, point_2):
    self.point_min_x = min(point_1[0], point_2[0])
    self.point_min_y = min(point_1[1], point_2[1])
    self.point_max_x = max(point_1[0], point_2[0])
    self.point_max_y = max(point_1[1], point_2[1])

  def get_pos(self):
    ”’координаты верхнего левого угла в виде кортежа”’
    return (self.point_min_x, self.point_max_y)

  def get_size(self):
    ”’возвращает размеры в виде кортежа”’
    self.size_x = round(abs(self.point_max_x – self.point_min_x), 2)
    self.size_y = round(abs(self.point_max_y – self.point_min_y), 2)
    return (self.size_x, self.size_y)

  def move(self, dx, dy):
    ”’изменяет положение на заданные значения”’
    self.point_min_x = round((self.point_min_x + dx), 2)
    self.point_max_x = round((self.point_max_x + dx), 2)
    self.point_min_y = round((self.point_min_y + dy), 2)
    self.point_max_y = round((self.point_max_y + dy), 2)

  def resize(self, width, height):
    ”’изменяет размер (положение верхнего левого угла остаётся неизменным)”’
    self.point_max_x = round((self.point_min_x + width), 2)
    self.point_min_y = round((self.point_max_y – height), 2)

Тимур
Тимур
Ответить на  Сергей Клочко
02.11.2024 12:25

Добавил два метода, но не помогло. Так же на третьем примере вылетает ошибка исполнения (RE)

Тимур
Тимур
Ответить на  Сергей Клочко
02.11.2024 21:11
class Rectangle():


    def __init__(self, point_1, point_2):
        self.point_min_x = min(point_1[0], point_2[0])
        self.point_min_y = min(point_1[1], point_2[1])
        self.point_max_x = max(point_1[0], point_2[0])
        self.point_max_y = max(point_1[1], point_2[1])


    def perimeter(self):
        self.perimeter = (abs(self.point_max_x - self.point_min_x) + abs(self.point_max_y - self.point_min_y)) * 2
        return round(self.perimeter, 2)


    def area(self):
        self.area = abs((self.point_max_x - self.point_min_x) * (self.point_max_y - self.point_min_y))
        return round(self.area, 2)
        
    def get_pos(self):
        '''координаты верхнего левого угла в виде кортежа'''
        return (self.point_min_x, self.point_max_y)


    def get_size(self):
        '''возвращает размеры в виде кортежа'''
        size_x = round(abs(self.point_max_x - self.point_min_x), 2)
        size_y = round(abs(self.point_max_y - self.point_min_y), 2)
        return (size_x, size_y)


    def move(self, dx, dy):
        '''изменяет положение на заданные значения'''
        self.point_min_x = round((self.point_min_x + dx), 2)
        self.point_max_x = round((self.point_max_x + dx), 2)
        self.point_min_y = round((self.point_min_y + dy), 2)
        self.point_max_y = round((self.point_max_y + dy), 2)


    def resize(self, width, height):
        '''изменяет размер (положение верхнего левого угла остаётся неизменным)'''
        self.point_max_x = round((self.point_min_x + width), 2)
        self.point_min_y = round((self.point_max_y - height), 2)
Тимур
Тимур
Ответить на  Сергей Клочко
03.11.2024 21:33

Я сдался на 20-ом примере. Никак не хочет проходить его. Через f форматирование слетает на 7 тесте, при умножении на 100 и округлении через int получается некорректный результат, а при округлении через round снова хрень) Пойду дальше, а эту задачу может как-нибудь потом попробую добить, если не брошу изучение.

Огромное спасибо за быстрые ответы!

Ольга
Ольга
07.11.2024 00:31

Сергей, здравствуйте.
Скажите, пожалуйста, свое мнение по поводу приведенного ниже кода. Яндекс его принимает.
Он похож на Ваш 2й вариант, но здесь верхний левый угол не определяется как экземпляр класса Point (соответственно, отсюда следуют различия с Вашим кодом).
Я просто хочу понять, есть ли какие-то недостатки в таком (моем) варианте? И, если более рациональным всё-таки является отнесение левого верхнего угла к отдельному классу (как у Вас), то почему?
А еще в этом случае (как в Вашем, так и в моем варианте) наличие или отсутствие округления в resize на результат не влияет – Яндекс принимает всё. Вероятно, потому, что в данном случае не проводятся никакие вычисления, а просто принимаются новые значения width и height (а они соответствуют «разрешенным» параметрам – в них исходно не более 2-х знаков после точки). Правильно ли я понимаю?

class Rectangle:

    def __init__(self, corner_1, corner_2) -> None:
        self.left_up = [min(corner_1[0], corner_2[0]), max(corner_1[1], corner_2[1])]
        self.right_down = [max(corner_1[0], corner_2[0]), min(corner_1[1], corner_2[1])]
        self.width = round(abs(self.left_up[0] - self.right_down[0]), 2)
        self.height = round(abs(self.left_up[1] - self.right_down[1]), 2)

    def perimeter(self):
        return round((self.width + self. height) * 2, 2)

    def area(self):
        return round(self.width * self. height, 2)

    def get_pos(self):
        return self.left_up[0], self.left_up[1]

    def get_size(self):
        return self.width, self.height

    def move(self, dx, dy):
        self.left_up = round(self.left_up[0] + dx, 2), round(self.left_up[1] + dy, 2)
        self.right_down = round(self.right_down[0] + dx, 2), round(self.right_down[1] + dy, 2)

    def resize(self, width, height):
        self.width = width
        self.height = height
Ольга
Ольга
Ответить на  Сергей Клочко
07.11.2024 13:46

Большое спасибо за подробный ответ!
Согласна, self.left_up.x, наверное,более читабельно, чем self.left_up[0].
С тестами Яндекса тоже понятно. Комментарии выше читала, но теперь, благодаря Вашему ответу, окончательно всё разложилось “по полочкам”.