代码之家  ›  专栏  ›  技术社区  ›  KubiK888

如何在Python中保护函数不受基类的影响?

  •  0
  • KubiK888  · 技术社区  · 6 年前

    我现在 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()
    

    如果无法防止基类中的方法被重写,我如何放置一些东西来发出自动警报/警告,指示基类中的特定方法已被重写?

    1 回复  |  直到 6 年前
        1
  •  1
  •   Martijn Pieters    6 年前

    你不能阻止子类使用相同的名称,不,你可以 保护 但是,通过给名称加上双下划线前缀,可以防止意外阴影:

    def __primitive_operation_3(self):
        print('Execute operation #3 from main class')
    

    Python编译器将替换 全部的 在类的方法中引用该名称,以添加类名作为前缀。这里,那是 AbstractClass ,因此实际名称变成 _AbstractClass__primitive_operation_3 ,但是因为编译器重写了所有引用,所以您可以透明地继续使用 __primitive_operation_3 在你的密码里。

    任何 __原语操作 子类上的名称将使用不同的前缀重命名,因为它们是在具有不同名称的类上定义的。

    此功能明确针对那些希望子类在其定义中使用广泛名称的基类。

    Reserved classes of identifiers section 在词法分析参考文献中:

    __*

    类私有名称。此类别中的名称在类定义的上下文中使用时,将重新编写为使用损坏的表单,以帮助避免基类和派生类的“private”属性之间的名称冲突。

    以及 Identifiers section 表达式文档:

    私名破译 :当在类定义中以文本形式出现的标识符以两个或多个下划线字符开头,而不是以两个或多个下划线结尾时,该标识符将被视为该类的私有名称。在为私有名称生成代码之前,将其转换为更长的形式。转换将在类名前面插入类名,去掉前导下划线并插入一个下划线。例如,标识符 __spam 在一个名为 Ham 将转换为 _Ham__spam . 这种转换独立于使用标识符的语法上下文。如果转换后的名称非常长(超过255个字符),则可能发生实现定义的截断。如果类名仅由下划线组成,则不进行转换。

    子类仍然可以重写名称,但必须显式地包含相同的前缀。

    请注意,不能使用此机制来避免特殊方法(带有前导和尾随 __ 双下划线,例如。 __init__ __len__ )在子类中被重写。如果基类的子类不能在不注意调用基类实现的情况下重写特定的方法,那么清除项目文档是至关重要的。充其量,您可以通过检查缺少的副作用来检测子类是否正在重写方法(标准库就是这样 protected Thread.__init__ overriding 或者你可以检查一下 self.methodname.__func__ is ClassObject.methodname 在调用方法之前仍然为true。

    推荐文章