如何保护 Python 中基数 class 的函数?
How to protect function from base class in Python?
我目前 learning python 中的模板方法模式。
我想知道是否有任何方法可以保护基class 中的某些函数,以便子class 无法覆盖?如下所示,subclass 中的 _primitive_operation_3
覆盖了基础 class.
中的相同函数
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()
并且如果无法阻止来自基础 class 的方法被覆盖,我如何放置一些东西来自动 alert/warning 指示来自基础 class 的特定方法已被覆盖?
你不能阻止子class使用相同的名字,不。您可以 保护 名称免受意外阴影,但是,通过给名称一个双下划线前缀:
def __primitive_operation_3(self):
print('Execute operation #3 from main class')
Python 编译器将在 class 的方法中替换对该名称的 所有 引用,以将 class 名称添加为一个前缀。在这里,那是 AbstractClass
,所以实际名称变成了 _AbstractClass__primitive_operation_3
,但是因为编译器重写了所有引用,所以您透明地继续在代码中使用 __primitive_operation_3
。
subclass 上的任何 __primitive_operation_3
名称都将使用不同的前缀重命名,只是因为它们是在 class 上定义的,具有不同的名称。
此功能明确针对希望允许子classes 在其定义中使用范围广泛的名称的基础 classes。
参见词法分析参考文档中的Reserved classes of identifiers section:
__*
Class-private names. Names in this category, when used within the context of a class definition, are re-written to use a mangled form to help avoid name clashes between “private” attributes of base and derived classes.
和表达式文档的Identifiers section:
Private name mangling: When an identifier that textually occurs in a class definition begins with two or more underscore characters and does not end in two or more underscores, it is considered a private name of that class. Private names are transformed to a longer form before code is generated for them. The transformation inserts the class name, with leading underscores removed and a single underscore inserted, in front of the name. For example, the identifier __spam
occurring in a class named Ham
will be transformed to _Ham__spam
. This transformation is independent of the syntactical context in which the identifier is used. If the transformed name is extremely long (longer than 255 characters), implementation defined truncation may happen. If the class name consists only of underscores, no transformation is done.
Subclasses 仍然可以覆盖名称,但必须明确包含相同的前缀。
请注意,您不能使用此机制来避免特殊方法(前导和尾随 __
双下划线,例如 __init__
或 __len__
)在子程序中被覆盖class。如果您的基础 class 的子 class 无法在不注意调用基础实现的情况下覆盖特定方法,则清晰的项目文档至关重要。充其量您可以通过检查缺少的副作用来检测 subclass 是否正在覆盖方法(这是标准库具有 的方式,或者您可以在之前检查 self.methodname.__func__ is ClassObject.methodname
是否为真调用方法。
我目前 learning python 中的模板方法模式。
我想知道是否有任何方法可以保护基class 中的某些函数,以便子class 无法覆盖?如下所示,subclass 中的 _primitive_operation_3
覆盖了基础 class.
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()
并且如果无法阻止来自基础 class 的方法被覆盖,我如何放置一些东西来自动 alert/warning 指示来自基础 class 的特定方法已被覆盖?
你不能阻止子class使用相同的名字,不。您可以 保护 名称免受意外阴影,但是,通过给名称一个双下划线前缀:
def __primitive_operation_3(self):
print('Execute operation #3 from main class')
Python 编译器将在 class 的方法中替换对该名称的 所有 引用,以将 class 名称添加为一个前缀。在这里,那是 AbstractClass
,所以实际名称变成了 _AbstractClass__primitive_operation_3
,但是因为编译器重写了所有引用,所以您透明地继续在代码中使用 __primitive_operation_3
。
subclass 上的任何 __primitive_operation_3
名称都将使用不同的前缀重命名,只是因为它们是在 class 上定义的,具有不同的名称。
此功能明确针对希望允许子classes 在其定义中使用范围广泛的名称的基础 classes。
参见词法分析参考文档中的Reserved classes of identifiers section:
__*
Class-private names. Names in this category, when used within the context of a class definition, are re-written to use a mangled form to help avoid name clashes between “private” attributes of base and derived classes.
和表达式文档的Identifiers section:
Private name mangling: When an identifier that textually occurs in a class definition begins with two or more underscore characters and does not end in two or more underscores, it is considered a private name of that class. Private names are transformed to a longer form before code is generated for them. The transformation inserts the class name, with leading underscores removed and a single underscore inserted, in front of the name. For example, the identifier
__spam
occurring in a class namedHam
will be transformed to_Ham__spam
. This transformation is independent of the syntactical context in which the identifier is used. If the transformed name is extremely long (longer than 255 characters), implementation defined truncation may happen. If the class name consists only of underscores, no transformation is done.
Subclasses 仍然可以覆盖名称,但必须明确包含相同的前缀。
请注意,您不能使用此机制来避免特殊方法(前导和尾随 __
双下划线,例如 __init__
或 __len__
)在子程序中被覆盖class。如果您的基础 class 的子 class 无法在不注意调用基础实现的情况下覆盖特定方法,则清晰的项目文档至关重要。充其量您可以通过检查缺少的副作用来检测 subclass 是否正在覆盖方法(这是标准库具有 self.methodname.__func__ is ClassObject.methodname
是否为真调用方法。