例:
class Parent(object): def __init__(self): self.someValue=1 def start(self): ''' Force method to be called''' self.someValue+=1
正确执行我想要我的孩子孩子班做的是:
class ChildCorrect(Parent): def start(self): Parent.start(self) self.someValue+=1
但是,有没有办法强制开发者开发Child类来专门调用(不只是覆盖)Parent类中定义的’start’方法,以防他们忘记调用它:
class ChildIncorrect(Parent): def start(self): '''Parent method not called,but correctly overridden''' self.someValue+=1
另外,如果这不是最佳做法,那又有什么办法呢?
解决方法
不,没有安全的方法来强迫用户打电话给超级用户.让我们来看几个可以达到或类似目标的选项,并讨论为什么这是一个坏主意.在下一节中,我还将讨论什么是明智的(相对于Python社区)来处理这种情况的方式.
>元类可以在子类定义时检查覆盖目标方法的方法(=是否与目标方法具有相同的名称)使用适当的参数调用super.
这需要深入的实现特定行为,例如使用CPython的dis
模块.在任何情况下,我都无法想象这是一个好主意 – 它取决于CPython的具体版本以及您正在使用CPython的事实.
元类可以与基础类合作.在这种情况下,baseclass在继承的方法被调用时通知元类,并且Metaclass使用一段保护代码封装任何重写方法.
守护代码测试在重写方法的执行过程中是否调用了继承的方法.这是有缺点的,需要针对需要这个“特征”的每个方法的单独的通知通道,并且线程安全性将是一个问题.此外,重写方法已经完成执行,您注意到它没有调用继承的方法,这可能会因为您的方案而不好.
它还打开了一个问题:如果重写方法没有称为继承方法,该怎么办?使用该方法的代码可能会引发异常(或者更糟的是,它可能认为该方法根本没有效果,这不是真的).
而且,迟来的反馈,开发人员超越了这个课程(如果他们得到所有的反馈!)是不好的.
>元类可以为每个覆盖方法生成一个保护代码,该方法在执行重写方法之前或之后自动调用继承的方法.
这里的缺点是开发人员不会期望继承的方法被自动调用,并且无法阻止该调用(例如,如果不满足子类的特殊条件),或者在其自己的覆盖方法中控制继承的方法是调用.
在编码python时,这违反了一大堆明智的原则(避免意外,明确比隐含更好,更可能更多).
>点3和4的组合.使用第3点的基类和元类的合作,来自第4点的保护码可以扩展为自动调用超级,如果覆盖方法没有称为超级本身.
再次,这是意想不到的,但它解决了重复超级调用的问题,以及如何处理不调用超级的方法.
但是,仍然存在问题.虽然线程安全性可以用线程本地化来修复,但是除非通过引发在所有情况下都不需要的异常,否则重写方法在没有满足前提条件的情况下中止超级调用超级.此外,超级只能在重写方法之后自动调用,而不是之前,在某些情况下,再次也是不希望的.
此外,这不是有助于在对象和类的生命周期内重新绑定属性,虽然可以通过使用描述符和/或扩展元类来处理该属性来帮助它.
为什么不这样做
Also,if this is not considered best practice,what would be an alternative?
使用Python的常见的最佳做法是假设您同意成年人.这意味着,除非你允许他们,否则没有人正在积极地尝试对你的代码做恶劣的事情.在这样一个生态系统中,在方法或类的文档中处理一个警告::这是有意义的,所以从该类继承的任何人都知道他们要做什么.
此外,在适当的时候调用超级方法在许多上下文中都是有意义的,开发人员使用基类将会考虑它,只会不小心忘记它.在这种情况下,使用上述第三点的元类不会帮助用户不必记住不要调用超级,这本身可能是一个问题,特别是对于有经验的程序员.
它也违反了最不奇怪的原则,“明确比隐含更好”(没有人期望继承的方法被隐含地调用!).这样一来,必须记录得很好,在这种情况下,您也可以诉诸于没有超级被自动调用,并且仅仅记录它比通常调用继承方法更有意义.