一个人也可以在raise NotImplementedError()
内部@abstractmethod
装饰一个基类方法的子 方法。
想象一下为一系列测量模块(物理设备)编写控制脚本。每个模块的功能都严格定义,仅实现一个专用功能:一个功能可以是一组继电器,另一个可以是多通道DAC或ADC,另一个可以是电流表等。
许多正在使用的低级命令将在模块之间共享,例如读取其ID号或向其发送命令。让我们看看现在的情况:
基类
from abc import ABC, abstractmethod
class Generic(ABC):
''' Base class for all measurement modules. '''
def __init__(self):
def _read_ID(self):
def _send_command(self, value):
共享动词
然后,我们意识到许多特定于模块的命令动词以及因此它们的接口逻辑也被共享。考虑到许多目标模块,下面是3个不同的动词,其含义将不言自明。
get(channel)
继电器:获取继电器的开/关状态channel
DAC:打开输出电压channel
ADC:打开输入电压channel
enable(channel)
中继:启用中继功能channel
DAC:启用对输出通道的使用channel
ADC:启用输入通道的使用channel
set(channel)
继电器:channel
打开/关闭继电器
DAC:将输出电压设置为开channel
ADC:嗯...没有什么逻辑可想到的。
共享动词成为强制动词
我认为上述动词在各个模块之间共享是一个很好的理由,因为我们看到它们的含义对于每个模块都是显而易见的。我将继续Generic
像这样编写我的基类:
class Generic(ABC):
@abstractmethod
def get(self, channel):
pass
@abstractmethod
def enable(self, channel):
pass
@abstractmethod
def set(self, channel):
pass
子类
现在我们知道子类都必须定义这些方法。让我们看一下ADC模块的外观:
class ADC(Generic):
def __init__(self):
super().__init__()
def get(self, channel):
def enable(self, channel):
您现在可能想知道:
但这对ADC模块不起作用,因为set
上面我们已经看到了这一点!
您说对了:不实施set
不是一种选择,因为当您尝试实例化ADC对象时,Python会在下面触发错误。
TypeError: Can't instantiate abstract class 'ADC' with abstract methods 'set'
因此,您必须执行一些操作,因为我们制作了set
一个强制动词(又名“ @abstractmethod”),该动词已由其他两个模块共享,但是同时,您也不得执行set
对此特定模块没有意义的任何
操作。
救援的NotImplementedError
通过像这样完成ADC类:
class ADC(Generic):
def set(self, channel):
raise NotImplementedError("Can't use 'set' on an ADC!")
您一次要做三件事:
- 您在保护用户免于错误地发出不是(也不应该!)对此模块实施的命令(“设置”)。
- 您正在明确地告诉他们问题出在哪里(有关为什么这很重要,请参见TemporalWolf的“裸机异常”链接)
- 您正在保护强制动词
确实有意义的所有其他模块的实现。即可以确保那些这些动词模块做有意义将实施这些方法和他们这样做究竟使用这些动词,而不是其他一些临时的名称。