Найти тему
Удалёнка

Python. Переопределение функционала базового класса

В прошлой статье класс Employee полностью перенимал функционал класса Person:

class Person:

def __init__(self, name):

self.__name = name   # имя человека

@property

def name(self):

return self.__name

def display_info(self):

print(f"Name: {self.__name} ")

class Employee(Person):

def work(self):

print(f"{self.name} works")

Но что, если мы хотим что-то изменить из этого функционала? Например, добавить работнику через конструктор, новый атрибут, который будет хранить компанию, где он работает или изменить реализацию метода display_info. Python позволяет переопределить функционал базового класса.

Например, изменим классы следующим образом:

class Person:

def __init__(self, name):

self.__name = name   # имя человека

@property

def name(self):

return self.__name

def display_info(self):

print(f"Name: {self.__name}")

class Employee(Person):

def __init__(self, name, company):

super().__init__(name)

self.company = company

def display_info(self):

super().display_info()

print(f"Company: {self.company}")

def work(self):

print(f"{self.name} works")

tom = Employee("Tom", "Microsoft")

tom.display_info()  # Name: Tom

# Company: Microsoft

Здесь в классе Employee добавляется новый атрибут - self.company, который хранит компания работника. Соответственно метод __init__() принимает три параметра: второй для установки имени и третий для установки компании. Но если в базом классе определен конструктор с помощью метода __init__, и мы хотим в производном классе изменить логику конструктора, то в конструкторе производного класса мы должны вызвать конструктор базового класса. То есть в конструкторе Employee надо вызвать конструктор класса Person.

Для обращения к базовому классу используется выражение super(). Так, в конструкторе Employee выполняется вызов:

super().__init__(name)

Это выражение будет представлять вызов конструктора класса Person, в который передается имя работника. И это логично. Ведь имя работника устанавливается именно в конструкторе класса Person. В самом конструкторе Employee лишь устанавливаем свойство company.

Кроме того, в классе Employee переопределяется метод display_info() - в него добавляется вывод компании работника. Причем мы могли определить этот метод следующим образом:

def display_info(self):

print(f"Name: {self.name}")

print(f"Company: {self.company}")

Но тогда строка вывода имени повторяла бы код из класса Person. Если эта часть кода совпадает с методом из класса Person, то нет смысла повторяться, поэтому опять же с помощью выражения super() обращаемся к реализации метода display_info в классе Person:

def display_info(self):

super().display_info()      # обращение к методу display_info в классе Person

print(f"Company: {self.company}")

Затем мы можем вызвать вызвать конструктор Employee для создания объекта этого класса и вызвать метод display_info:

tom = Employee("Tom", "Microsoft")

tom.display_info()

Консольный вывод программы:

Name: Tom
Company: Microsoft

Проверка типа объекта

При работе с объектами бывает необходимо в зависимости от их типа выполнить те или иные операции. И с помощью встроенной функции isinstance() мы можем проверить тип объекта. Эта функция принимает два параметра:

isinstance(object, type)

Первый параметр представляет объект, а второй - тип, на принадлежность к которому выполняется проверка. Если объект представляет указанный тип, то функция возвращает True. Например, возьмем следующую иерархию классов Person-Employee/Student:

class Person:

def __init__(self, name):

self.__name = name   # имя человека

@property

def name(self):

return self.__name

def do_nothing(self):

print(f"{self.name} does nothing")

#  класс работника

class Employee(Person):

def work(self):

print(f"{self.name} works")

#  класс студента

class Student(Person):

def study(self):

print(f"{self.name} studies")

def act(person):

if isinstance(person, Student):

person.study()

elif isinstance(person, Employee):

person.work()

elif isinstance(person, Person):

person.do_nothing()

tom = Employee("Tom")

bob = Student("Bob")

sam = Person("Sam")

act(tom)    # Tom works

act(bob)    # Bob studies

act(sam)    # Sam does nothing

Здесь класс Employee определяет метод work(), а класс Student - метод study.

Здесь также определена функция act, которая проверяет с помощью функции isinstance, представляет ли параметр person определнный тип, и зависимости от результатов проверки обращается к определенному методу объекта.