我很好奇在Python中是否有一种方法(从Parent类强制)强制在子类被重写时从子类调用父方法。
例:
class Parent(object):
def __init__(self):
self.someValue=1
def start(self):
''' Force method to be called'''
self.someValue+=1
我希望我的孩子Child班做的正确实现是:
class ChildCorrect(Parent):
def start(self):
Parent.start(self)
self.someValue+=1
但是,有一种方法可以迫使开发子类的开发人员专门调用(而不是覆盖)父类中定义的“开始”方法,以防万一他们忘记调用它:
class ChildIncorrect(Parent):
def start(self):
'''Parent method not called, but correctly overridden'''
self.someValue+=1
此外,如果这不是最佳做法,那还有什么替代方法?
不,没有安全的方法来强迫用户调用超级。让我们讨论一些可以达到该目标或类似目标的选项,并讨论为什么这是一个坏主意。在下一节中,我还将讨论处理这种情况的明智方式(相对于Python社区)。
一个元类可以在定义子类时检查是否有覆盖目标方法的方法(与目标方法具有相同的名称)是否使用适当的参数调用了super。
这需要深入实现特定的行为,例如使用dis
CPython模块。在任何情况下,我都无法想象这是一个好主意-它取决于CPython的特定版本以及您完全使用CPython的事实。
元类可以与基类合作。在这种情况下,基类会在调用继承的方法时通知元类,而元类会用一段保护代码包装所有重写方法。
保护代码测试在执行重写方法期间是否调用了继承的方法。不利之处在于,每种方法都需要一个单独的通知通道来使用此“功能”,此外,线程安全性和重入也是一个问题。此外,在您注意到它尚未调用继承方法的时候,重写方法已经完成了执行,根据情况的不同,该方法可能很糟糕。
它还提出了一个问题:如果重写方法未调用继承方法,该怎么办?使用该方法的代码引发异常可能是意外的(或者更糟的是,它可能假定该方法完全无效,这是不正确的)。
同样,开发人员重写类的最新反馈(如果他们完全得到了反馈!)也是不好的。
一个元类可以为每个被重写的方法生成一条保护代码,该方法可以在重写方法执行之前或之后自动调用继承的方法。
不利的一面是,开发人员不会期望继承的方法会被自动调用,并且无法停止该调用(例如,如果未满足子类专用的先决条件)或无法控制自己的重写方法中的继承方法叫。
这在编写python时违反了很多明智的原则(避免意外,显式优于隐式,并且可能更多)。
点2和点3的组合。使用点2的基类和元类的协作,可以扩展点3的保护代码以自动调用super(如果覆盖方法尚未调用super本身)。
同样,这是意外的,但是它解决了重复的超级调用以及如何处理不调用超级的方法的问题。
但是,仍然存在问题。尽管线程安全性可以通过线程局部变量来固定,但是当不满足先决条件时,除了通过引发并非在所有情况下都可能需要的异常之外,覆盖方法仍然没有办法中止对super的调用。同样,super只能在覆盖方法之后自动调用,而不能在覆盖方法之前自动调用,这在某些情况下也是不可取的。
同样,尽管可以通过使用描述符和/或扩展元类来照顾它,但这些都不能帮助在对象和类的生存期内重新绑定属性。
此外,如果这不是最佳做法,那还有什么替代方法?
使用Python的常见最佳做法是假设您属于成年人。这意味着,除非您允许,否则没有人会积极尝试对您的代码执行令人讨厌的事情。在这样的生态系统中,有必要.. warning::
在方法或类的文档中加上“ a ”,这样从该类继承的任何人都知道他们必须做什么。
同样,在许多情况下在适当的位置调用super方法是有意义的,以至于使用基类的开发人员无论如何都会考虑它,而只是偶然地忘记了它。在这种情况下,使用上面第三点的元类也无济于事–用户必须记住不要调用super,这本身就是一个问题,特别是对于有经验的程序员而言。
它也违反了最小惊喜原则,“显式优于隐式”(没有人期望继承的方法被隐式调用!)。再次,这必须被很好地记录下来,在这种情况下,您也可以诉诸于没有自动调用super的情况,而只是证明调用继承方法比平时更有意义。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句