Super: примеры (PYTHON)

Полное руководство по функции super в Python
Раздел: Встроенные функции, Наследование
super(type: type, object_or_type: type): super object

Описание функции super

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

Использование функции особенно актуально в случаях:

  • Переопределения методов с сохранением функциональности родительского класса
  • Работы с множественным наследованием и соблюдения порядка разрешения методов (MRO)
  • Вызова инициализатора родительского класса в __init__
  • Создания расширяемых и поддерживаемых иерархий классов

Функция принимает два необязательных аргумента:

  • type - класс, для которого ищется родительский метод
  • object_or_type - объект экземпляра или класс

Возможные формы вызова:

  • super() - автоматически определяет класс и экземпляр (работает только внутри методов)
  • super(type, object_or_type) - явное указание параметров

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

Базовые примеры использования

Пример простого наследования с вызовом родительского метода:

class Animal:
    def __init__(self, name):
        self.name = name
    
    def speak(self):
        return 'Звук животного'

class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name)
        self.breed = breed
    
    def speak(self):
        return f'{super().speak()}: Гав!'

dog = Dog('Шарик', 'Овчарка')
print(dog.name)
print(dog.speak())
Шарик
Звук животного: Гав!

Пример с явным указанием аргументов:

class A:
    def method(self):
        return 'A'

class B(A):
    def method(self):
        parent_result = super(B, self).method()
        return f'B -> {parent_result}'

obj = B()
print(obj.method())
B -> A

Вызов метода без создания экземпляра:

class Base:
    @classmethod
    def create(cls):
        return f'Создан из {cls.__name__}'

class Derived(Base):
    @classmethod
    def create(cls):
        return f'Производный -> {super(Derived, cls).create()}'

print(Derived.create())
Производный -> Создан из Derived

Похожие подходы в Python

Прямой вызов метода родительского класса по имени:

class Parent:
    def work(self):
        return 'Работа родителя'

class Child(Parent):
    def work(self):
        result = Parent.work(self)
        return f'Дочерний: {result}'

c = Child()
print(c.work())
Дочерний: Работа родителя

Особенности разных подходов:

  • Прямой вызов по имени класса - проще для понимания в простых иерархиях, но нарушает инкапсуляцию и не работает с множественным наследованием
  • Функция super() - поддерживает динамическое разрешение методов, следует MRO, рекомендуется для сложных иерархий
  • Делегирование через композицию - альтернатива наследованию, когда функциональность передается через атрибуты объектов

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

Аналоги в других языках программирования

В JavaScript используется ключевое слово super:

class Animal {
    constructor(name) {
        this.name = name;
    }
    speak() {
        return `${this.name} издает звук`;
    }
}

class Dog extends Animal {
    constructor(name, breed) {
        super(name);
        this.breed = breed;
    }
    speak() {
        return super.speak() + ' - Гав!';
    }
}

const dog = new Dog('Шарик', 'овчарка');
console.log(dog.speak());
Шарик издает звук - Гав!

В Java ключевое слово super:

class Animal {
    String speak() {
        return 'Звук животного';
    }
}

class Dog extends Animal {
    @Override
    String speak() {
        return super.speak() + ': Гав!';
    }
}

Dog dog = new Dog();
System.out.println(dog.speak());
Звук животного: Гав!

В PHP используется parent:::

class Animal {
    public function speak() {
        return 'Звук животного';
    }
}

class Dog extends Animal {
    public function speak() {
        return parent::speak() . ': Гав!';
    }
}

$dog = new Dog();
echo $dog->speak();
Звук животного: Гав!

В C# используется base:

class Animal {
    public virtual string Speak() {
        return 'Звук животного';
    }
}

class Dog : Animal {
    public override string Speak() {
        return base.Speak() + ': Гав!';
    }
}

var dog = new Dog();
Console.WriteLine(dog.Speak());
Звук животного: Гав!

Типичные ошибки

Вызов super() вне метода класса:

class MyClass:
    attr = super()  # Ошибка

try:
    obj = MyClass()
except RuntimeError as e:
    print(f'Ошибка: {e}')
Ошибка: super(): no arguments

Неправильный порядок аргументов:

class A:
    def method(self):
        return 'A'

class B(A):
    def method(self):
        try:
            return super(self, B).method()  # Неверный порядок
        except TypeError as e:
            return f'Ошибка: {e}'

obj = B()
print(obj.method())
Ошибка: super(type, obj): obj must be an instance or subtype of type

Забытый вызов super().__init__() при переопределении конструктора:

class Parent:
    def __init__(self):
        self.initialized = True

class Child(Parent):
    def __init__(self):
        # Вызов super().__init__() отсутствует
        self.child_attr = 'значение'

c = Child()
print(f'initialized: {hasattr(c, "initialized")}')
print(f'child_attr: {c.child_attr}')
initialized: False
child_attr: значение

Изменения в последних версиях Python

В Python 3.0 упростили синтаксис вызова super(), разрешив использование без аргументов внутри методов класса.

В Python 3.3 улучшена производительность и добавлена оптимизация для частых случаев использования.

В Python 3.6 добавлена поддержка автоматического определения класса в __class__ для нулевых аргументов super().

В Python 3.10 появились более информативные сообщения об ошибках при некорректном использовании super().

В Python 3.11 была оптимизирована работа super() для повышения скорости выполнения.

Расширенные примеры

Множественное наследование и MRO:

Пример python
class A:
    def process(self):
        return 'A'

class B(A):
    def process(self):
        return f'B -> {super().process()}'

class C(A):
    def process(self):
        return f'C -> {super().process()}'

class D(B, C):
    def process(self):
        return f'D -> {super().process()}'

print(D.__mro__)
d = D()
print(d.process())
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
D -> B -> C -> A

Использование с дескрипторами и property:

Пример python
class ValidatedAttribute:
    def __init__(self, validator):
        self.validator = validator
        self.data = {}
    
    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        return self.data.get(id(obj))
    
    def __set__(self, obj, value):
        self.data[id(obj)] = self.validator(value)

class Person:
    def __init__(self, name):
        self.name = name
    
    @property
    def name(self):
        return self._name
    
    @name.setter
    def name(self, value):
        if not isinstance(value, str):
            raise TypeError('Имя должно быть строкой')
        self._name = value

class Employee(Person):
    def __init__(self, name, position):
        super().__init__(name)
        self.position = position
    
    @property
    def name(self):
        original = super().name
        return f'Сотрудник: {original}'
    
    @name.setter
    def name(self, value):
        super(Employee, Employee).name.__set__(self, value)

emp = Employee('Иван', 'менеджер')
print(emp.name)
Сотрудник: Иван

Кооперативное наследование с миксинами:

Пример python
class LoggerMixin:
    def log(self, message):
        print(f'Лог [{self.__class__.__name__}]: {message}')
        try:
            super().log(message)  # Вызов следующего метода в MRO
        except AttributeError:
            pass  # Если метод log отсутствует в родителях

class SerializableMixin:
    def serialize(self):
        return f'Объект {self.__class__.__name__}'

class BaseProcessor:
    def process(self):
        self.log('Начало обработки')
        result = 'Результат обработки'
        self.log('Конец обработки')
        return result

class AdvancedProcessor(LoggerMixin, SerializableMixin, BaseProcessor):
    def process(self):
        self.log('Расширенная обработка')
        result = super().process()
        return f'Улучшенный: {result}'

processor = AdvancedProcessor()
print(processor.process())
print(processor.serialize())
Лог [AdvancedProcessor]: Расширенная обработка
Лог [AdvancedProcessor]: Начало обработки
Лог [AdvancedProcessor]: Конец обработки
Улучшенный: Результат обработки
Объект AdvancedProcessor

Динамическое определение классов:

Пример python
def create_class_hierarchy(base_classes):
    class DynamicClass(*base_classes):
        def __init__(self, value):
            # Вызов super() работает динамически
            super().__init__()
            self.value = value
        
        def get_value(self):
            return f'Значение: {self.value}'
    
    return DynamicClass

class A:
    def __init__(self):
        self.a_init = True

class B:
    def __init__(self):
        self.b_init = True

DynamicClass = create_class_hierarchy([A, B])
obj = DynamicClass(42)
print(obj.get_value())
print(f'a_init: {obj.a_init}')
print(f'b_init: {obj.b_init}')
Значение: 42
a_init: True
b_init: True

питон super function comments

En
Super Return proxy object