Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When calling super() in a derived class, can I pass in self.__class__? [duplicate]

I've recently discovered (via StackOverflow) that to call a method in a base class I should call:

super([[derived class]], self).[[base class method]]()

That's fine, it works. However, I find myself often copying and pasting between classes when I make a change and frequently I forget to fix the derived class argument to the super() function.

I'd like to avoid having to remember to change the derived class argument. Can I instead just use self.__class__ as the first argument of the super() function?

It seems to work but are there good reasons why I shouldn't do this?

like image 471
Simon Tewsi Avatar asked Aug 13 '13 12:08

Simon Tewsi


People also ask

What is the effect of calling super () __ Init__?

__init__() of the superclass ( Square ) will be called automatically. super() returns a delegate object to a parent class, so you call the method you want directly on it: super(). area() . Not only does this save us from having to rewrite the area calculations, but it also allows us to change the internal .

What does self __ class __ do?

self. __class__ is a reference to the type of the current instance. Throwing an exception here is like using an assert statement elsewhere in your code, it protects you from making silly mistakes. type() should be preferred over self.

What is super () __ init __ in Python?

The “__init__” is a reserved method in python classes. It is known as a constructor in Object-Oriented terminology. This method when called, allows the class to initialize the attributes of the class. Python super() The super() function allows us to avoid using the base class name explicitly.

What super () does in Python?

The super() function is used to give access to methods and properties of a parent or sibling class. The super() function returns an object that represents the parent class.


2 Answers

No you cannot. The super() call needs to know what class the method is part of, to search the base classes for an overridden method.

If you pass in self.__class__ (or better still, type(self)) then super() is given the wrong starting point to search for methods, and will end up calling its own method again.

See it as a pointer in the list of classes that form the Method Resolution Order sequence. If you pass in type(self) then the pointer will refer to any subclasses instead of the original starting point.

The following code leads to an infinite recursion error:

class Base(object):     def method(self):         print 'original'  class Derived(Base):     def method(self):         print 'derived'         super(type(self), self).method()  class Subclass(Derived):     def method(self):         print 'subclass of derived'         super(Subclass, self).method() 

Demo:

>>> Subclass().method() subclass of derived derived derived derived  <... *many* lines removed ...>    File "<stdin>", line 4, in method   File "<stdin>", line 4, in method   File "<stdin>", line 4, in method RuntimeError: maximum recursion depth exceeded while calling a Python object 

because type(self) is Subclass, not Derived, in Derived.method().

In the example, the MRO for Subclass is [Subclass, Derived, Base], and super() needs to know where to start searching for any overridden methods. By using type(self) you tell it to start at Subclass, so it'll find Derived.method() next, which is where we started.

like image 90
Martijn Pieters Avatar answered Oct 14 '22 16:10

Martijn Pieters


self.__class__ might not be a subclass, but rather a grandchild-or-younger class, leading to a stack-breaking loop.

like image 42
Ignacio Vazquez-Abrams Avatar answered Oct 14 '22 16:10

Ignacio Vazquez-Abrams