class Square(Rectangle):
"""Klasa reprezentująca kwadrat.
Dziedziczy po klasie Rectangle reprezentującej prostokąt, jako że kwadrat jest prostokątem.
"""
def __init__(self, size: float):
"""Konstruktor klasy.
Jako że klasa Square dziedziczy po klasie Rectangle wymagane jest wywołanie konstruktora klasy rodzica.
Wykonujemy to pisząc super().__init__(argumenty).
Argumenty:
size - długość boku
"""
super().__init__(size, size)
class Ellipse(Figure):
"""Klasa reprezentująca elipsę.
Dziedziczy po klasie Figure.
"""
def __init__(self, radius1: float, radius2: float):
"""
Konstruktor klasy.
Jako że klasa Ellipse dziedziczy po klasie abstrakcyjnej Figure, nie wywołujemy konstruktora klasy rodzica.
Argumenty:
radius1 - pierwszy promień elipsy
radius2 - drugi promień elipsy
"""
self._radius1 = radius1
self._radius2 = radius2
def area(self):
"""Metoda obliczająca pole elipsy. Nie została zaimplementowana."""
raise NotImplemented
def perimeter(self):
"""Metoda obliczająca obwód elipsy. Nie została zaimplementowana."""
raise NotImplemented
class Circle(Ellipse):
"""Klasa reprezentująca koło.
Dziedziczy po klasie Ellipse reprezentującej elipsę, jako że koło jest też elipsą.
"""
def __init__(self, radius: float):
"""Konstruktor klasy.
Jako że klasa Circle dziedziczy po klasie Ellipse wymagane jest wywołanie konstruktora klasy rodzica.
Wykonujemy to pisząc super().__init__(argumenty).
Argumenty:
radius - promień koła
"""
super().__init__(radius, radius)
@classmethod
def one(cls):
"""Metoda klasowa tworząca koło o promieniu 1.
Taki sposób pozwala na utworzenie dodatkowych "konstruktorów".
"""
return cls(1)
@property
def radius(self):
"""Promień koła. Getter.
Wartość tylko do odczytu, nie ma metody setter.
"""
return self._radius1
def area(self) -> float:
"""Metoda obliczająca pole koła."""
return pi * (self.radius ** 2)
def perimeter(self) -> float:
"""Metoda obliczająca obwód koła."""
return 2 * pi * self.radius
if __name__ == "__main__":
# figure = Figure() - Błąd, nie możemy utworzyć obiektu klasy z abstrakcyjnymi metodami
quad = Quad(1, 2, 3, 4, 5, 6, 30)
rectangle = Rectangle(1, 2)
square = Square(1)
ellipse = Ellipse(1, 2)
circle = Circle(5)
quad.__d1 = 10 # Działa, ale nie jest poprawne, __d1 jest prywatne
print(f"quad.__d1 = {quad.__d1}") # Działa, ale nie jest poprawne, __d1 jest prywatne
quad._sides[0] = 10 # Działa, ale nie jest poprawne, _sides jest protected
print(f"quad._sides[0] = {quad._sides[0]}") # Działa, ale nie jest poprawne, _sides jest protected
rectangle.width = 10 # Działa
print(f"rectangle.width = {rectangle.width}") # Działa
# circle.radius = 10 # Nie działa, nie ma settera
print(f"circle.radius = {circle.radius}") # Działa
circle_one = Circle.one() # Wywołanie metody klasowej
print(f"kwadrat jest figurą: {isinstance(square, Figure)}")
print(f"kwadrat jest czworokątem: {isinstance(square, Quad)}")
print(f"kwadrat jest prostokątem: {isinstance(square, Rectangle)}")
print(f"kwadrat jest kwadratem: {isinstance(square, Square)}")
print(f"kwadrat jest elipsą: {isinstance(square, Ellipse)}")
print(f"kwadrat jest kołem: {isinstance(square, Circle)}")
print(f"kwadrat jest typu: {type(square)}")
selection = randint(1, 5)
figure = None
if selection == 1:
figure = Quad(1, 2, 3, 4, 6, 7, 30)
elif selection == 2:
figure = Rectangle(1, 2)
elif selection == 3:
figure = Square(1)
elif selection == 4:
figure = Ellipse(1, 2)
elif selection == 5:
figure = Circle(1)
print(f"Wylosowana figura jest typu: {type(figure)}")
if isinstance(figure, Rectangle):
# Sprawdzamy, czy figure jest prostokątem, a jeśli tak, to wypisujemy jego wysokość.
# Przy takim podejściu środowisko będzie podpowiadać metody dostępne w klasie Rectangle i traktować figure jako Rectangle.
print(f"Wysokość: {figure.height}")