我目前正在用learning编写python的模板方法模式。
我想知道是否有任何方法可以保护基类中的一些函数,以致子类不会被覆盖?如下所示,来自子类的_primitive_operation_3
覆盖了来自基类的相同函数。
import abc
class AbstractClass(metaclass=abc.ABCMeta):
"""
Define abstract primitive operations that concrete subclasses define
to implement steps of an algorithm.
Implement a template method defining the skeleton of an algorithm.
The template method calls primitive operations as well as operations
defined in AbstractClass or those of other objects.
"""
def template_method(self):
self._primitive_operation_1()
self._primitive_operation_2()
self._primitive_operation_3()
# Functions must be specified by subclass (i.e., subclass variant)
@abc.abstractmethod
def _primitive_operation_1(self):
pass
# Functions must be specified by subclass (i.e., subclass variant)
@abc.abstractmethod
def _primitive_operation_2(self):
pass
# Functions inherited and not modified by subclass (i.e., subclass invariant)
def _primitive_operation_3(self):
print ('Execute operation #3 from main class')
class ConcreteClass(AbstractClass):
"""
Implement the primitive operations to carry out
subclass-specificsteps of the algorithm.
"""
def _primitive_operation_1(self):
pass
def _primitive_operation_2(self):
pass
# You can still overwrite it if you want
def _primitive_operation_3(self):
print ('Execute operation #3 from subclass')
def main():
concrete_class = ConcreteClass()
concrete_class.template_method()
if __name__ == "__main__":
main()
如果不能防止基类中的方法被覆盖,我如何在适当的位置自动发出警告/警告,指示基类中的特定方法已被覆盖?
发布于 2019-04-16 02:18:59
你不能阻止子类使用相同的名字,不。但是,您可以通过为名称添加双下划线前缀来防止名称被意外遮蔽:
def __primitive_operation_3(self):
print('Execute operation #3 from main class')
Python编译器将在类的方法中替换对该名称的所有引用,以将类名添加为前缀。这里是AbstractClass
,所以实际名称变成了_AbstractClass__primitive_operation_3
,但是因为编译器会重写所有引用,所以在代码中透明地继续使用__primitive_operation_3
。
子类上的任何__primitive_operation_3
名称都将使用不同的前缀进行重命名,这只是因为它们是在具有不同名称的类上定义的。
这个特性明确地针对基类,这些基类希望允许子类在其定义中使用广泛的名称。
请参阅词法分析参考文档中的 section:
__*
类-私有名称。当在类定义的上下文中使用时,此类别中的名称将被重写为使用损坏的形式,以帮助避免基类和派生类的“私有”属性之间的名称冲突。
和表达式文档的 section:
私有名称损坏:当以文本形式出现在类定义中的标识符以两个或更多下划线字符开头且不以两个或更多下划线结尾时,它被认为是该类的私有名称。私有名称在为其生成代码之前被转换为更长的形式。转换将插入类名,并在名称前面删除前导下划线并插入单个下划线。例如,在名为
Ham
的类中出现的标识符__spam
将被转换为_Ham__spam
。此转换独立于使用标识符的语法上下文。如果转换后的名称非常长(超过255个字符),则可能会发生实现定义的截断。如果类名只包含下划线,则不会执行任何转换。
子类仍然可以覆盖该名称,但必须显式包含相同的前缀。
请注意,您不能使用此机制来避免特殊方法(具有前导和尾随的__
双下划线,例如__init__
或__len__
)在子类中被重写。如果基类的子类不能在不注意调用基类的情况下覆盖特定的方法,那么清晰的项目文档是至关重要的。在最好的情况下,您可以通过检查缺少的副作用来检测子类是否覆盖了方法(这就是标准库具有protected Thread.__init__
overriding的方式,或者您可以在调用方法之前检查self.methodname.__func__ is ClassObject.methodname
是否仍然为真。
https://stackoverflow.com/questions/55695067
复制相似问题