Сообщить об ошибке.

Функция super() в Python, доступ к унаследованным методам.

Обеспечивает доступ к оригиналам наследованных методов.

Синтаксис:

super(type, object-or-type)

Параметры:

  • type - необязательно, тип, от которого начинается поиск объекта-посредника
  • object-or-type - необязательно, тип или объект, определяет порядок разрешения метода для поиска

Возвращаемое значение:

  • объект-посредник, делегирующий вызовы методов родителю или собрату класса.

Описание:

Функция super(), возвращает объект объект-посредник, который делегирует вызовы метода родительскому или родственному классу, указанного type типа. Это полезно для доступа к унаследованным методам, которые были переопределены в классе.

object-or-type определяет порядок разрешения метода __mro__ для поиска. Поиск начинается с класса, сразу после указанного типа. Например, если __mro__ - это D -> B -> C -> A -> object, а значение type=B, то super() выполняет поиск объекта C -> A -> object.

  • Если object-or-type не указан, то возвращается несвязанный объект-посредник.
  • Если object-or-type является объектом (экземпляром), то будет получен посредник, для которого isinstance(obj, type) возвращает True.
  • Если object-or-type является типом (классом), то будет получен посредник, для которого issubclass(subtype, type) возвращает True.

Типичные случаи использования super():

  1. В иерархиях с единичным наследованием используется для обращения к родительским классам, чтобы явно не указывать их имена, это упрощает поддержку кода в дальнейшем. Еще примеры.

    Например:

    >>> class A:
    ...     def some_method(self):
    ...         print('some_method A')
    ... 
    >>> class B(A):
    ...     def some_method(self):
    ...         print('some_method B')
    ... 
    >>> x = B()
    >>> x.some_method()
    # some_method B
    

    Здесь перегружен метод родительского класса. Но что, если необходимо немного дополнить родительский метод, не копируя его полностью? Тут и нужна функция super():

    >>> class A:
    ...     def some_method(self):
    ...         print('some_method A')
    ... 
    >>> class B(A):
    ...     def some_method(self):
    ...         super().some_method()
    ...         print('some_method B')
    ... 
    >>> x = B()
    >>> x.some_method()
    # some_method A
    # some_method B
    
  2. Для поддержки совместного множественного наследования в динамическом окружении. Он делает возможным обращение с ромбовидными иерархиями, при которых несколько базовых классов задают реализацию метода с одним и тем же именем.

Использование функция super() с обоими аргументами точно определяет объекты и делает соответствующие ссылки. Без аргументов функция super() работает только внутри определения класса, а необходимые детали для идентификации класса и доступа к текущему экземпляру для методов заполняет компилятор.

В дополнение к поиску методов, super() также работает для поиска атрибутов. Одним из вариантов использования этого является вызов дескрипторов в родительском или родственном классе.

Обратите внимание, что super() реализована как часть процесса привязки для явного поиска по точечным атрибутам, таких как super().__getitem__(name). Это достигается путем реализации собственного метода __getattribute__() для поиска классов в предсказуемом порядке, который поддерживает кооперативное множественное наследование __mro__. super() и не предназначена для неявных поисков с использованием инструкций или операторов, таких как super()[name].

Примеры получения доступа к унаследованным методам.

Функция в единичном наследовании:

class Computer():
    def __init__(self, computer, ram, ssd):
        self.computer = computer
        self.ram = ram
        self.ssd = ssd

# Если создать дочерний класс `Laptop`, то будет доступ 
# к свойству базового класса благодаря функции super().
class Laptop(Computer):
    def __init__(self, computer, ram, ssd, model):
        super().__init__(computer, ram, ssd)
        self.model = model


lenovo = Laptop('lenovo', 2, 512, 'l420')

print('This computer is:', lenovo.computer)
print('This computer has ram of', lenovo.ram)
print('This computer has ssd of', lenovo.ssd)
print('This computer has this model:', lenovo.model)
# Вывод
# This computer is: lenovo
# This computer has ram of 2
# This computer has ssd of 512
# This computer has this model: l420

В следующем примере класс Rectangle является суперклассом, а Square является подклассом, поскольку методы Square наследуются от Rectangle, то мы можем вызвать метод __init __() суперкласса (Rectangle.__ init __()) из класса Square используя функцию super(). Далее просто пользоваться методами родителя, не написав ни строчки кода. В данном случае квадрат - это частный случай прямоугольника...

class Rectangle:
    def __init__(self, length, width):
        self.length = length
        self.width = width

    def area(self):
        return self.length * self.width

    def perimeter(self):
        return 2 * self.length + 2 * self.width

class Square(Rectangle):
    def __init__(self, length):
        # Для квадрата просто нужно передать один параметр length.
        # При вызове 'super().__init__()' установим атрибуты 'length' и 'width'.
        super().__init__(length, length)


# Класс 'Square' явно не реализует метод 'area()' и 
# будет использовать его из суперкласса 'Rectangle'
sqr = Square(4)
print("Area of Square is:", sqr.area())
# Area of Square is: 16

rect = Rectangle(2, 4)
print("Area of Rectangle is:", rect.area())
# Area of Rectangle is: 8

И наконец пример работы функции super() при использовании множественного наследования:

class A:
    def __init__(self):
        print('Initializing: class A')

    def sub_method(self, b):
        print('sub_method from class A:', b)


class B(A):
    def __init__(self):
        print('Initializing: class B')
        super().__init__()

    def sub_method(self, b):
        print('sub_method from class B:', b)
        super().sub_method(b + 1)

class X(B):
    def __init__(self):
        print('Initializing: class X')
        super().__init__()

    def sub_method(self, b):
        print('sub_method from class X:', b)
        super().sub_method(b + 1)


class Y(X):
    def __init__(self):
        print('Initializing: class Y')
        # super() с параметрами
        super(X, self).__init__()

    def sub_method(self, b):
        print('sub_method from class Y:', b)
        super().sub_method(b + 1)


x = X()
x.sub_method(1)
print('Обратите внимание как происходит инициализация')
print('классов при указании аргументов в функции super()')
y = Y()
y.sub_method(5)

# Вывод

# Initializing: class X
# Initializing: class B
# Initializing: class A
# sub_method from class X: 1
# sub_method from class B: 2
# sub_method from class A: 3
# обратите внимание как происходит инициализация
# классов при указании аргументов в функции super()
# Initializing: class Y
# Initializing: class B
# Initializing: class A
# sub_method from class Y: 5
# sub_method from class X: 6
# sub_method from class B: 7
# sub_method from class A: 8