class Rectangle:

    __slots__ = '__width', 'height'

    def __init__(self, a, b):
        self.width = a
        self.height = b

    @property
    def width(self):
        return self.__width
    
    @width.setter
    def width(self, value):
        print("Setter called")
        self.__width = value

    @property
    def perimetr(self):
        return (self.height + self.width) * 2

    @property
    def area(self):
        return self.height * self.width

# У класса наследника будет атрибут __dict__ если не задать атрибут __slots__
class Square(Rectangle):
    
    # этот slots расширяет имена родительского класса
    __slots__ = 'color'

    def __init__(self, a, b, color):
        super().__init__(a, b)
        self.color = color


def main():
    a = Rectangle(3, 4)
    b = Rectangle(5, 6)

    print(b.perimetr, b.area)


    s = Square(3, 6, 'red')
    # print(s.__dict__)

if __name__ == '__main__':
    main()