这是OO语言的正常行为吗?

时间:2011-02-10 20:39:52

标签: python oop

我已经定义了这个类:

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

并覆盖了这种方法:

def total_form_count(self):
    return self._total_form_count

恰好super(...).__init__在该函数的某处使用total_form_count()。它调用我的函数而不是基类中定义的函数。

我想我想是因为我打电话给super()它会使用自己的东西,但显然在Python中并非如此。这是否适用于其他语言,如C#?如果我调用基础构造函数,它仍然会从那里调用所有派生函数?

7 个答案:

答案 0 :(得分:4)

是的,这是通过动态调度调用子类方法的典型OOP行为(多态)。这是C#要求程序员将可覆盖的方法标记为virtual的部分原因。我相信你一般都熟悉这个概念,而这个惊喜主要来自这个事实,即这是在构造函数中发生的。

正如您所观察到的,这在构造函数中可能非常危险,因为超类的构造函数可以调用子类的方法,该方法可能依赖于在子类的构造函数中初始化的属性。这个问题在Effective Java中有明确说明,你可以在这里阅读更多相关信息:What's wrong with overridable method calls in constructors?

答案 1 :(得分:3)

这是正常行为。请注意第一个参数: self 。这是对调用方法的对象的引用,因此即使调用超类方法,方法调用的任何重写方法也将是子类方法。

我知道强制它使用超类方法的唯一方法是使用未绑定的引用,即SuperClass.overridenMethod(self, param1, param2) ...

答案 2 :(得分:3)

你听说过多态吗?如果没有,你不知道OOP是什么,应该查找它。

基类构造函数使用的self当然是派生类的实例(相同的 self),所以当它调用self.m()时,动态调度m的实现。一些OO语言需要动态调度的方法的显式注释(virtual关键字) - 尽管(正如@Doc Brown指出的那样)它在C ++中的构造函数中不起作用 - 而其他语言则将其作为默认值。无论如何,多态性是OOP的重要组成部分,虽然在某些语言中可以获得静态分派,但多态性在许多语言中都是唯一的选项,而在所有其他语言中通常是首选的方式。所以是的,这是正常行为。

答案 3 :(得分:3)

这是python中的正常行为,C#具有相同的行为(对于虚函数),C ++没有(有些人认为这是C ++的设计缺陷)。在C ++中,如果从构造函数或其他成员函数调用覆盖虚函数,则会有所不同。原因是当超类的构造函数运行时,V表不完整。

答案 4 :(得分:1)

在C ++中,您可以根据total_form_count是否声明virtual来选择这两种行为。但是在Python中,所有方法都表现得像virtual:对象将始终使用对象的实际类型中的方法。

答案 5 :(得分:0)

在C ++中,构造函数是一种特殊情况,对虚方法的调用导致调用类本身的方法(而不是虚拟链的叶子上的方法)。

答案 6 :(得分:0)

是的,这是一种名为polymorphism的行为。每种OOP语言中的方法查找都是从对象实例的类中完成的,而不是代码所在的类。