class Geom:
name = 'Geom'
class Line:
def draw(self):
print('Рисование линии')
g = Geom()
l = Line()
Пусть есть два класса. Очевидно что артибуты одного из другого мы никак не можем получить при такой схеме реализации. У них разное пространство имён.
Но можем установить связь между ними, например, чтобы открытые атрибуты Geom были доступны в классе Line :
class Line(Geom):
def draw(self):
print('Рисование линии')
Теперь можем получить
l.name # GeomНаследование - когда один класс определяется на основе другого. Причем, класс Geom называется родительским или базовым, а класс Line – подклассом родительского или дочерним классом.
Что это такое - понятно. Теперь для чего это нужно - разберемся на примере.
Добавим метод для установки координат в класс Line
def set_coords(self, x1, y1, x2, y2):
self.x1 = x1
self.y1 = y1
self.x2 = x2
self.y2 = y2
А затем создадим еще одну фигуру, допустим прямоугольник Rect, и у него тоже будет метод установки координат. Но тогда получится дублирование кода. И метод выше мы можем вынести(определить) в базовом классе Geom.
Почему так работает? Ведь конкретно данного метода set_coords(self) нет в дочерних класса(Rect, Line). Но когда интерпретатор его там не находит, то продолжает искать у родителей. Причем 'self' из этого метода будет ссылаться не на объект базового класса, а на тот экземпляр(объект) из которого он был вызван! Это важный момент.(картинку с пояснением увидите в комментариях). Всё зависит от того откуда метод set_coords() был вызван.
Почему это важно? Например, здесь self формирует локальные свойства/артибуты для дочерних классов Line, Rect.
Немножко вредных советов от НеУспенского:
Создали так(обратите внимание на последнюю строчку)
class Geom:
name = 'Geom'
def set_coords(self, x1, y1, x2, y2):
self.x1 = x1
self.y1 = y1
self.x2 = x2
self.y2 = y2
self.draw()
Запустили (ниже):
l = Line()
r = Rect()
l.set_coords(1, 1, 2 , 2)
r.set_coords(1, 1, 2 , 2)
Сработает или ошибка из-за отсутствия метода draw() в базовом классе?🧐А если set_coords() вызовем через объект класса Geom?🧐
Делаем вывод: При реализации методов в классах следует придерживаться одного простого правила: внутри них обращаться только к разрешенным атрибутам либо внутри текущего класса, либо базовых классов. Но не дочерних.
Все тоже самое применимо при обращении к свойствам базового класса.
Можем там же переопределять атрибуты/методы в дочерних классах, например: 👇
class Line(Geom):
name = 'Line'
Это очень похоже на систему поиска атрибутов/методов у объекта класса vs самого класса. Сначала ищется у экземпляра, а если не находит, то ищет в классе. Самые базовые понятие, если с ними разобрались, то и наследование пойдёт тоже легко (проверю))). Тоже самое в наследовании, сначала ищет в текущем классе, а потом в родительских, поднимаясь вверх по иерархии.
Пример наследования init() в дочернем классе:
class Table:
def __init__(self, model, color):
self.model = model
self.color = color
class RoundTable(Table): # пример для реализации наследования
def __init__(self, model, color, radius, height):
# super() здесь вызывает "старый" инит и устанавливает переданные атрибуты (обычный вызов функции)
super().__init__(model, color)
self.radius = radius
self.height = height
Оставляйте фидбек по материалу 👇
🔥 — Огонь, приму на вооружение!
🤔 — Знал, но освежил память.
💬 — Есть вопросы в комментарии!