1

I've defined this class:

class RequiredFormSet(BaseFormSet):
    def __init__(self, *args, **kwargs):
        super(RequiredFormSet, self).__init__(*args, **kwargs)

And overridden this method:

def total_form_count(self):
    return self._total_form_count

It so happens that super(...).__init__ uses total_form_count() somewhere in that function. It's calling my function rather than the one defined in the base class.

I guess I thought because I called super() it would use its own stuff, but apparently in Python that's not true. Is this the way it works in other languages, like C#? If I call the base constructor, it will still call all the derived functions from there?

mpen
  • 272,448
  • 266
  • 850
  • 1,236

7 Answers7

4

Yes, this is typical OOP behavior (polymorphism) to have subclass methods invoked by dynamic dispatch. This is part of the reason why C# requires the programmer to mark an overridable method as virtual. I'm sure you're familiar with this notion in general, and the surprise mainly comes from the fact that this is happening in a constructor.

As you have observed, this can be very dangerous in constructors because a superclass's constructor can invoke a subclass's method that may rely on properties initialized in the subclass's constructor. This problem is explicitly noted in Effective Java, and you can read more about it here: What's wrong with overridable method calls in constructors?

Community
  • 1
  • 1
ide
  • 19,942
  • 5
  • 64
  • 106
  • Yeah, that's the problem I was having. I needed some stuff to be initialized in the base class first, which is why I was calling its init right away, but then that was trying to call some stuff in my derived class, and I wound up with a catch 22. Not good :) – mpen Feb 10 '11 at 21:14
3

This is normal behavior. Note the first argument: self. That's a reference to the object the methods are being called on, so even when you call a superclass method, any overridden methods that method calls will be the subclass methods.

The only way I know of to force it to use a superclass method is with an unbound reference, ie SuperClass.overridenMethod(self, param1, param2)...

Mitch Lindgren
  • 2,120
  • 1
  • 18
  • 36
3

Have you heard of polymorphism? If not, you have no idea what OOP is about and should look it up.

The self the base class constructor uses is of course an instance of the derived class (the same self), so when it calls self.m(), the implementation of m is dispatched dynamically. Some OO languages require explicit annotation of methods that are dispatched dynamically (virtual keyword) - although (as @Doc Brown pointed out) it doesn't work in constructors specifically in C++ - while others make it the default. Anyway, polymorphism is an essential part of OOP and although it's possible in some languages to get static dispatch, polymorphism is the only option in many languages and the generally preferred way in all others. So yes, this is the normal behaviour.

  • ...yes, I'm fully aware of polymorphism, virtual methods, and all that jazz. I was thinking, if you can instantiate an instance of Derived,... wait...nevermind. Makes sense now, just wasn't thinking clearly. – mpen Feb 10 '11 at 21:11
3

This is normal behaviour in python, C# has the same behaviour (for virtual functions), C++ has not (some people consider that as a design flaw of C++). In C++, it makes a difference if you call an overriden virtual function from the constructor or from another member function. The reason for that is that when the constructor of a superclass runs, the V-table is not complete.

Doc Brown
  • 19,739
  • 7
  • 52
  • 88
  • C++ has it, just not as default (which, yes, is a design flaw IMHO in a language that claims to be OO). –  Feb 10 '11 at 20:48
  • No, when you call a virtual function from the constructor of a class in C++, the overriden function in the subclass won't be called! – Doc Brown Feb 10 '11 at 20:50
  • I stand corrected =/ But it only affects constructors? Well, that's would be weird. –  Feb 10 '11 at 20:56
1

In C++, you can choose between the two behaviors based on whether total_form_count is declared virtual or not. But in Python, all methods behave like virtual: the object will always use the methods from the actual type of the object.

Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
  • 1
    The question was about what happens in the `__init__` function of the class, which is the constructor in C++. Declaring a function as virtual does not help for that case - the overriden function won't be called either. See my answer. – Doc Brown Feb 10 '11 at 20:57
0

In C++ the constructor is a kind of special case, the calls to virtual methods result in calling the methods of the class itself (not the one at the leaf of the virtual chain).

jdehaan
  • 19,700
  • 6
  • 57
  • 97
0

Yes, it's a behaviour called polymorphism. Method lookup in every OOP language is done from the class of the object instance, not the one where the code resides.

vz0
  • 32,345
  • 7
  • 44
  • 77