Python вызов конструктора суперкласса

Обновлено: 17.05.2024

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

Синтаксис:

Параметры:

  • 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() :

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

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

Для поддержки совместного множественного наследования в динамическом окружении. Он делает возможным обращение с ромбовидными иерархиями, при которых несколько базовых классов задают реализацию метода с одним и тем же именем.

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

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

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

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

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

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

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

In all other languages I've worked with the super constructor is invoked implicitly. How does one invoke it in Python? I would expect super(self) but this doesn't work.

you should emphasize that an answer that doesn't use the Derived Class name is what you want. e.g. (pseudocode): super().__init__(args. )

you should be accepting Aidan Gomez's answer. It would save us a lot of time, since it has an answer in both python 2 and 3.

@Mike I think there's still value in an answer that lists the Python 2 way, because there's a lot of old Python 2 code floating around out there, and some of the people who wind up at this question probably won't otherwise know how to make sense of it. (And despite it being EOL, many people do still write code in Python 2, either because they don't know better or because some organizational requirement has forced it on them.)

I have changed the accepted answer to @Aiden Gomez's answer. Though Ignacio was correct, @Aidan's was the most appropriate as of today given Python 3's changes to super()

7 Answers 7

In line with the other answers, there are multiple ways to call super class methods (including the constructor), however in Python-3.x the process has been simplified:

Python-3.x

Python-2.x

In python 2.x, you have to call the slightly more verbose version super(, self) , which is equivalent to super() as per the docs.

super() returns a parent-like object in new-style classes:

just of curiosity why does super(B,self) require both B and self to be mentioned? isn't this redundant? shouldn't self contain a reference to B already?

With respect to the documentation of super() , you should be able to write super().__init__() wothout arguments.

With Python 2.x old-style classes it would be this:

@kdbanman: This will work with new-style classes, but one of the reasons to use new-style classes is to not have to do it this way. You can use super and not have to directly name the class you're inheriting from.

One way is to call A's constructor and pass self as an argument, like so:

The advantage of this style is that it's very clear. It call A's initialiser. The downside is that it doesn't handle diamond-shaped inheritance very well, since you may end up calling the shared base class's initialiser twice.

Another way is to use super(), as others have shown. For single-inheritance, it does basically the same thing as letting you call the parent's initialiser.

However, super() is quite a bit more complicated under-the-hood and can sometimes be counter-intuitive in multiple inheritance situations. On the plus side, super() can be used to handle diamond-shaped inheritance. If you want to know the nitty-gritty of what super() does, the best explanation I've found for how super() works is here (though I'm not necessarily endorsing that article's opinions).

I've seen super being used quite a lot in classes with only single inheritance. I can see why you'd use it in multiple inheritance but am unclear as to what the advantages are of using it in this kind of situation.

11 Answers 11

What's the difference?

means to call SomeBaseClass 's __init__ . while

means to call a bound __init__ from the parent class that follows SomeBaseClass 's child class (the one that defines this method) in the instance's Method Resolution Order (MRO).

If the instance is a subclass of this child class, there may be a different parent that comes next in the MRO.

Explained simply

When you write a class, you want other classes to be able to use it. super() makes it easier for other classes to use the class you're writing.

As Bob Martin says, a good architecture allows you to postpone decision making as long as possible.

super() can enable that sort of architecture.

When another class subclasses the class you wrote, it could also be inheriting from other classes. And those classes could have an __init__ that comes after this __init__ based on the ordering of the classes for method resolution.

Without super you would likely hard-code the parent of the class you're writing (like the example does). This would mean that you would not call the next __init__ in the MRO, and you would thus not get to reuse the code in it.

If you're writing your own code for personal use, you may not care about this distinction. But if you want others to use your code, using super is one thing that allows greater flexibility for users of the code.

Python 2 versus 3

This works in Python 2 and 3:

This only works in Python 3:

It works with no arguments by moving up in the stack frame and getting the first argument to the method (usually self for an instance method or cls for a class method - but could be other names) and finding the class (e.g. Child ) in the free variables (it is looked up with the name __class__ as a free closure variable in the method).

I used to prefer to demonstrate the cross-compatible way of using super , but now that Python 2 is largely deprecated, I will demonstrate the Python 3 way of doing things, that is, calling super with no arguments.

Indirection with Forward Compatibility

What does it give you? For single inheritance, the examples from the question are practically identical from a static analysis point of view. However, using super gives you a layer of indirection with forward compatibility.

Forward compatibility is very important to seasoned developers. You want your code to keep working with minimal changes as you change it. When you look at your revision history, you want to see precisely what changed when.

You may start off with single inheritance, but if you decide to add another base class, you only have to change the line with the bases - if the bases change in a class you inherit from (say a mixin is added) you'd change nothing in this class.

In Python 2, getting the arguments to super and the correct method arguments right can be a little confusing, so I suggest using the Python 3 only method of calling it.

If you know you're using super correctly with single inheritance, that makes debugging less difficult going forward.

Dependency Injection

Other people can use your code and inject parents into the method resolution:

Say you add another class to your object, and want to inject a class between Foo and Bar (for testing or some other reason):

Using the un-super child fails to inject the dependency because the child you're using has hard-coded the method to be called after its own:

However, the class with the child that uses super can correctly inject the dependency:

Addressing a comment

Why in the world would this be useful?

Python linearizes a complicated inheritance tree via the C3 linearization algorithm to create a Method Resolution Order (MRO).

We want methods to be looked up in that order.

For a method defined in a parent to find the next one in that order without super , it would have to

  1. get the mro from the instance's type
  2. look for the type that defines the method
  3. find the next type with the method
  4. bind that method and call it with the expected arguments

The UnsuperChild should not have access to InjectMe . Why isn't the conclusion "Always avoid using super "? What am I missing here?

The UnsuperChild does not have access to InjectMe . It is the UnsuperInjector that has access to InjectMe - and yet cannot call that class's method from the method it inherits from UnsuperChild .

Both Child classes intend to call a method by the same name that comes next in the MRO, which might be another class it was not aware of when it was created.

The one without super hard-codes its parent's method - thus is has restricted the behavior of its method, and subclasses cannot inject functionality in the call chain.

The one with super has greater flexibility. The call chain for the methods can be intercepted and functionality injected.

You may not need that functionality, but subclassers of your code may.

Conclusion

Always use super to reference the parent class instead of hard-coding it.

What you intend is to reference the parent class that is next-in-line, not specifically the one you see the child inheriting from.

Not using super can put unnecessary constraints on users of your code.

In C, DI is like this. code is here. If I add one more implementation of list interface, say doublylinkedlist then the application smoothly picks it. I can make my example more configurable by introducing config.txt and link implementation at load time. Is this the right example? If yes,How do I relate your code? See the first adv of DI in wiki. Where is any new implementation configurable? in your code

A new implementation is created through inheritance, for example, where one of the "Injector" classes inherits from the InjectMe class. Comments aren't for discussion, however, so I suggest you discuss this further with others in chat or ask a new question on the main site.

great answer! but when using multiple inheritance, there are complications with super() and __init__ functions. especially if the signature of __init__ varies between classes in the hierarchy. I've added an answer that focuses on this aspect

Thank you for this super()-verbose answer! I could not find anywhere else how the second argument is deduced in the Python 3 syntax (i.e. “moving up in the stack frame and getting the first argument to the method”). Seems strange they settled with this implicit syntax: less typing but somewhat inconsistent with the way things are done elsewhere within the class code where you need to always specify self explicitly (e.g. no implicit object-variable resolution).

@RomanShapovalov I recall doing the research on that, but I don't exactly recall where I found it - I think in the super object definition (written in C) in the source code. I would start there if you're looking to verify that the mechanism remains the same. However the mechanism works, it would still be an implementation detail that you're not expected to look at too closely, regardless.

The benefits of super() in single-inheritance are minimal -- mostly, you don't have to hard-code the name of the base class into every method that uses its parent methods.

However, it's almost impossible to use multiple-inheritance without super() . This includes common idioms like mixins, interfaces, abstract classes, etc. This extends to code that later extends yours. If somebody later wanted to write a class that extended Child and a mixin, their code would not work properly.

I had played a bit with super() , and had recognized that we can change calling order.

In this case MRO of D will be (only for Python 3):

Let's create a class where super() calls after method execution.

So we can see that resolution order is same as in MRO. But when we call super() in the beginning of the method:

We have a different order it is reversed a order of the MRO tuple.

For additional reading I would recommend next answers:

I dont understand why the order is changing. The first part I understand that D-B-C-A because D is the first class, then when load the self(B,C) will eventually print B, C then only A since B(A),C(A) pointed back to self for the final part. If I follow this understanding, then shouldnt the second part be like B-C-A-D? Could you please explain a little to me please.

My bad, I didnt notice that every each class instance has been initiated with super() first. Then if that is the case, shouldnt it be A-B-C-D? I somehow understand how A-C-B-D came to but still couldnt convince and still have a bit confuse. my understanding is that, d = D() called the Class D(B,C) with 2 self-parameters, since super() is initiated first then B is called together with it's attributes then D is not printed before C is because Class D(B,C) contains 2 self-parameters so it must execute the second one which is Class C(A), after executed there is not more self-parameters to executed

It's very easy to understand the second one as long as you get the first one. It is just like a stack. you push the print'' into stack and do super(), when it's done the A, it starts to print things in that stack, so the order is reverse.

It is like a recursion. What it does in the second example, it calls all classes first, puts them in the queue (or stack) because super() is called first. Then when it gets to the base class, it executes the base class' print method and goes down to the next one in the queue (or in the stack as @grantsun said). And in the first example D's print() is called first that's why it prints "I'm from D" first and only then it goes to the next class where it again sees print() first and again only then calls super()

Doesn't all of this assume that the base class is a new-style class?

Will not work in Python 2. class A must be new-style, i.e: class A(object)

When calling super() to resolve to a parent's version of a classmethod, instance method, or staticmethod, we want to pass the current class whose scope we are in as the first argument, to indicate which parent's scope we're trying to resolve to, and as a second argument the object of interest to indicate which object we're trying to apply that scope to.

Consider a class hierarchy A , B , and C where each class is the parent of the one following it, and a , b , and c respective instances of each.

Using super with a staticmethod

e.g. using super() from within the __new__() method

1- even though it's usual for __new__() to take as its first param a reference to the calling class, it is not implemented in Python as a classmethod, but rather a staticmethod. That is, a reference to a class has to be passed explicitly as the first argument when calling __new__() directly:

2- when calling super() to get to the parent class we pass the child class A as its first argument, then we pass a reference to the object of interest, in this case it's the class reference that was passed when A.__new__(cls) was called. In most cases it also happens to be a reference to the child class. In some situations it might not be, for instance in the case of multiple generation inheritances.

3- since as a general rule __new__() is a staticmethod, super(A, cls).__new__ will also return a staticmethod and needs to be supplied all arguments explicitly, including the reference to the object of insterest, in this case cls .

4- doing the same thing without super

Using super with an instance method

e.g. using super() from within __init__()

1- __init__ is an instance method, meaning that it takes as its first argument a reference to an instance. When called directly from the instance, the reference is passed implicitly, that is you don't need to specify it:

2- when calling super() within __init__() we pass the child class as the first argument and the object of interest as a second argument, which in general is a reference to an instance of the child class.

3- The call super(A, self) returns a proxy that will resolve the scope and apply it to self as if it's now an instance of the parent class. Let's call that proxy s . Since __init__() is an instance method the call s.__init__(. ) will implicitly pass a reference of self as the first argument to the parent's __init__() .

4- to do the same without super we need to pass a reference to an instance explicitly to the parent's version of __init__() .

Using super with a classmethod

1- A classmethod can be called from the class directly and takes as its first parameter a reference to the class.

2- when calling super() within a classmethod to resolve to its parent's version of it, we want to pass the current child class as the first argument to indicate which parent's scope we're trying to resolve to, and the object of interest as the second argument to indicate which object we want to apply that scope to, which in general is a reference to the child class itself or one of its subclasses.

3- The call super(B, cls) resolves to the scope of A and applies it to cls . Since alternate_constructor() is a classmethod the call super(B, cls).alternate_constructor(. ) will implicitly pass a reference of cls as the first argument to A 's version of alternate_constructor()

4- to do the same without using super() you would need to get a reference to the unbound version of A.alternate_constructor() (i.e. the explicit version of the function). Simply doing this would not work:

The above would not work because the A.alternate_constructor() method takes an implicit reference to A as its first argument. The cls being passed here would be its second argument.

How do I initialize the SuperClass __init__ in the subclass? I am following the Python tutorial and it doesn't cover that. When I searched on Google, I found more than one way of doing. What is the standard way of handling this?

4 Answers 4

Python (until version 3) supports "old-style" and new-style classes. New-style classes are derived from object and are what you are using, and invoke their base class through super() , e.g.

Because python knows about old- and new-style classes, there are different ways to invoke a base method, which is why you've found multiple ways of doing so.

For completeness sake, old-style classes call base methods explicitly using the base class, i.e.

But since you shouldn't be using old-style anymore, I wouldn't care about this too much.

Python 3 only knows about new-style classes (no matter if you derive from object or not).

As of python 3.5.2, you can use:

will work (I prefer the 2nd one, as it adheres more to the DRY principle).

wrong. super only works with new-style classes, and is the only proper way to call a base when using new-style classes. Furthermore, you also need to pass 'self' explicitly using the old-style construct.

@Ivo - the OP gave a new-style class in the example, and there's little point in talking about the difference between new-style and old-style as no one should use old-style any more. The link I gave (to the Python docs) suggest that there's more than one "proper" way to call the super-class __init__ .

How do I initialize the base (super) class?

Use a super object to ensure you get the next method (as a bound method) in the method resolution order. In Python 2, you need to pass the class name and self to super to lookup the bound __init__ method:

In Python 3, there's a little magic that makes the arguments to super unnecessary - and as a side benefit it works a little faster:

Hardcoding the parent like this below prevents you from using cooperative multiple inheritance:

Note that __init__ may only return None - it is intended to modify the object in-place.

Something __new__

There's another way to initialize instances - and it's the only way for subclasses of immutable types in Python. So it's required if you want to subclass str or tuple or another immutable object.

You might think it's a classmethod because it gets an implicit class argument. But it's actually a staticmethod. So you need to call __new__ with cls explicitly.

We usually return the instance from __new__ , so if you do, you also need to call your base's __new__ via super as well in your base class. So if you use both methods:

Python 3 sidesteps a little of the weirdness of the super calls caused by __new__ being a static method, but you still need to pass cls to the non-bound __new__ method:

Сегодня в этом руководстве мы обсудим метод super() в Python. Перед тем, как погрузиться в тему, мы настоятельно рекомендуем изучить руководство по наследованию Python.

метод super

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

Или просто он используется для вызова конструктора, то есть метода __init__() суперкласса.

В версиях Python 3.x мы можем использовать super без передачи двух вышеуказанных параметров. Посмотрите на приведенный ниже фрагмент кода.

Здесь C — производный класс, B — базовый класс, method — определяемая пользователем функция с аргументом arg .

Как видите, строка super().method(arg) super( C, self).method(arg) фактически эквивалентна super( C, self).method(arg) в Python 3.x. Это запрещено в Python 2.x. Следовательно, использовать super там сложно.

Использование super()

Рассмотрим приведенный ниже пример.

вывод

В приведенном выше примере классы, производные от базового класса Demo не были реализованы эффективно или надежно.

Производный класс Newdemo явно инициализирует значения полей A, B и C базового класса. Такое же дублирование кода обнаруживается при инициализации тех же полей в базовом классе, в том числе Demo .

Этот процесс неэффективен. Это означает, что подклассу должен быть предоставлен доступ к членам суперкласса.

Следовательно, всякий раз, когда подклассу нужно обратиться к своему непосредственному суперклассу, на super выходит super .

Super() для вызова конструктора суперкласса

Теперь применим метод super() к приведенному выше примеру.

пример super

Здесь производный класс Newdemo вызывает super() с аргументами a, b и c. Это вызывает __init__ конструктора __init__ базового класса, т.е. Demo . Это инициализирует значения a, b и c. Следовательно, класс Newdemo больше не инициализирует сами значения.

Использование super в Python 2.x

Синтаксис для вызова конструктора super в Python 2.x приведен ниже.

Следовательно, нам нужно внести некоторые незначительные изменения в приведенный выше пример, если мы хотим использовать его в Python 2.

Во-первых, нам нужно поместить object в базовый класс, как показано ниже.

А во-вторых, пройти Newdemo и self на месте вызова суперкласса. Нравится.

Зачем нужен super()

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

Далее, для многоуровневого наследования super может использоваться для неявной ссылки на непосредственный суперкласс. Это снова упрощает понимание кода и упрощает обслуживание.

Читайте также: