I've defined this class:
class RequiredFormSet(BaseFormSet):
def __init__(self, *args, **kwargs):
s开发者_JS百科uper(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?
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?
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)
...
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.
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.
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.
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).
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.
精彩评论