我已经定义了这个类:
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#?如果我调用基础构造函数,它仍然会从那里调用所有派生函数?
答案 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语言中的方法查找都是从对象实例的类中完成的,而不是代码所在的类。