Передача определённых параметров из инициализатора родительского класса
Есть вполне себе простая задачка по подсчету площади в дочерних классах "столов"
import math
class Desk:
def __init__(self, width: int = 0, length: int = 0, radius: int = 0):
self._width = width
self._length = length
self._radius = radius
class RectDesk(Desk):
def area(self):
return self._width * self._length
class RoundDesk(Desk):
def area(self):
return round(math.pi * self._radius**2, 2)
rect_desk = RectDesk(20, 10)
print(rect_desk.__dict__)
print(rect_desk.area())
rect_desk2 = RectDesk(20, 20)
print(rect_desk2.__dict__)
print(rect_desk2.area())
round_desk = RoundDesk(radius=20)
print(round_desk.__dict__)
print(round_desk.area())
Однако у меня возник вопрос, можно ли каким-то образом передавать не все параметры из инициализатора родительского класса? Очевидно, что для подсчета "Прямоугольного стола" мне не нужен радиус, однако все равно он передается.
При переопределении инициализатора, все равно просит радиус
class Desk:
def __init__(self, width, length, radius):
self._width = width
self._length = length
self._radius = radius
def area(self):
raise NotImplementedError("In child class must be area calculating method")
class RectDesk(Desk):
def __init__(self, width, length):
super().__init__(width, length)
Traceback (most recent call last):
File "B:\python\hws\Desks.py", line 27, in <module>
rect_desk = RectDesk(20, 10)
File "B:\python\hws\Desks.py", line 16, in __init__
super().__init__(width, length)
TypeError: Desk.__init__() missing 1 required positional argument: 'radius'
Ответы (2 шт):
Вы не совсем верно понимаете наследование, дочерние классы должны расширять базовый класс, а не сжимать его.
Советую почитать про базовые принципы ООП и SOLID.
В данном случае у вас общее у всех объектов типа стол то, что у всех таких объектов можно посчитать площадь. Других сходств нет, входные параметры сильно отличаются в зависимости от типа, поэтому гораздо логичнее реализовать интерфейс типа Desk с обязательным для реализации методом area (и вы кстати сами к этому пришли во второй вашей попытке, где выдаете NotImplementedError при расчете площади в базовом классе).
В Python в качестве альтернативы интерфейсу можно использовать абстрактный класс ABC.
Правильная архитектура на мой взгляд должна выглядеть как-то так:
import math
from abc import ABC, abstractmethod
class Desk(ABC):
@abstractmethod
def area(self):
pass
class RectDesk(Desk):
def __init__(self, width, length):
self._width = width
self._length = length
def area(self):
return self._width * self._length
class RoundDesk(Desk):
def __init__(self, radius):
self._radius = radius
def area(self):
return round(math.pi * self._radius ** 2, 2)
rect_desk = RectDesk(20, 10)
print(rect_desk.__dict__)
print(rect_desk.area())
round_desk = RoundDesk(20)
print(round_desk.__dict__)
print(round_desk.area())
В предыдущем ответе верно сказали - это не очень хорошая идея, конструировать классы таким образом. Однако тебе может понадобиться перегрузить класс из чужой библиотеки, убрав лишние параметры, поэтому твой вопрос вполне уместен.
Вариант 1: Если готов править родительский класс
class Desk:
def __init__(self, width=None, length=None, radius=None):
if not width is None:
self._width = width
if not length is None:
self._length = length
if not radius is None:
self._radius = radius
class RectDesk(Desk):
def __init__(self, width, length):
super().__init__(width, length)
Здесь будут инициализированы только те переменные, которые были переданы в super().init
Вариант 2: Если не готов править родительский класс
class RectDesk(Desk):
def __init__(self, width, length):
super().__init__(width, length, None)
#Если хочется, чтобы таких параметров у класса не было совсем, то можно их удалить:
del self.radius