是为了记住自己和你的团队正确实施课程吗?我没有完全使用这样的抽象类:
class RectangularRoom(object):
def __init__(self, width, height):
raise NotImplementedError
def cleanTileAtPosition(self, pos):
raise NotImplementedError
def isTileCleaned(self, m, n):
raise NotImplementedError
Run Code Online (Sandbox Code Playgroud)
Uri*_*iel 51
正如文档所述[docs],
在用户定义的基类中,抽象方法在需要派生类重写方法时,或者在开发类以指示仍需要添加实际实现时,应引发此异常.
请注意,虽然主要陈述的用例此错误是应该在继承类上实现的抽象方法的指示,但无论如何您都可以使用它,比如指示TODO标记.
Jér*_*ôme 24
正如Uriel所说,它适用于抽象类中应该在子类中实现的方法,但也可用于指示TODO.
第一个用例有一个替代方案:Abstract Base Classes.那些有助于创建抽象类.
这是一个Python 3示例:
class C(abc.ABC):
@abstractmethod
def my_abstract_method(self, ...):
...
Run Code Online (Sandbox Code Playgroud)
实例化时C,你会得到一个错误,因为它my_abstract_method是抽象的.您需要在子类中实现它.
TypeError: Can't instantiate abstract class C with abstract methods my_abstract_method
Run Code Online (Sandbox Code Playgroud)
子类C和实现my_abstract_method.
class D(C):
def my_abstract_method(self, ...):
...
Run Code Online (Sandbox Code Playgroud)
现在你可以实例化了D.
C.my_abstract_method不必是空的.它可以从D使用中调用super().
这种优势的一个优点NotImplementedError是,您可以Exception在实例化时获得显式,而不是在方法调用时获得.
Tem*_*olf 17
考虑是否相反:
class RectangularRoom(object):
def __init__(self, width, height):
pass
def cleanTileAtPosition(self, pos):
pass
def isTileCleaned(self, m, n):
pass
Run Code Online (Sandbox Code Playgroud)
并且你继承并且忘记告诉它如何isTileCleaned()或者,或许更可能的是,它是错误的isTileCLeaned().然后在你的代码中,None当你调用它时,你会得到一个.
None有效的输出?谁知道. raise NotImplmentedError 强制你实现它,因为当你尝试运行它时会抛出异常,直到你这样做.这消除了很多无声错误.它类似于为什么裸露的除了几乎从来都不是一个好主意:因为人们犯错误,这确保他们不会被扫地.
注意:正如其他答案所提到的那样,使用抽象基类更好,因为错误是前载的,程序在实现之前不会运行(使用NotImplementedError,它只会在实际调用时抛出异常).
pfa*_*bri 17
还可以raise NotImplementedError() 在@abstractmethod-decorated 基类方法的 child 方法 内部执行 a 。
想象一下为一系列测量模块(物理设备)编写控制脚本。每个模块的功能都被严格定义,仅实现一个专用功能:一个可以是继电器阵列,另一个是多通道 DAC 或 ADC,另一个是电流表等。
使用中的许多低级命令将在模块之间共享,例如读取它们的 ID 号或向它们发送命令。让我们看看此时我们有什么:
from abc import ABC, abstractmethod #< we'll make use of these later
class Generic(ABC):
''' Base class for all measurement modules. '''
# Shared functions
def __init__(self):
# do what you must...
def _read_ID(self):
# same for all the modules
def _send_command(self, value):
# same for all the modules
Run Code Online (Sandbox Code Playgroud)
然后我们意识到许多特定于模块的命令动词以及它们的接口逻辑也是共享的。这里有 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): # ...continued
@abstractmethod
def get(self, channel):
pass
@abstractmethod
def enable(self, channel):
pass
@abstractmethod
def set(self, channel):
pass
Run Code Online (Sandbox Code Playgroud)
我们现在知道我们的子类都必须定义这些方法。让我们看看 ADC 模块的样子:
class ADC(Generic):
def __init__(self):
super().__init__() #< applies to all modules
# more init code specific to the ADC module
def get(self, channel):
# returns the input voltage measured on the given 'channel'
def enable(self, channel):
# enables accessing the given 'channel'
Run Code Online (Sandbox Code Playgroud)
您现在可能想知道:
但这对ADC模块不起作用,
set因为我们刚刚在上面看到的那样毫无意义!
你是对的:不实现set不是一个选项,因为当你尝试实例化你的 ADC 对象时,Python 会触发下面的错误。
TypeError: Can't instantiate abstract class 'ADC' with abstract methods 'set'
Run Code Online (Sandbox Code Playgroud)
所以你必须实现一些东西,因为我们做了set一个强制动词(又名“@abstractmethod”),它被其他两个模块共享,但同时,你也不能实现任何set对这个特定模块没有意义的东西
。
通过像这样完成 ADC 课程:
class ADC(Generic): # ...continued
def set(self, channel):
raise NotImplementedError("Can't use 'set' on an ADC!")
Run Code Online (Sandbox Code Playgroud)
你同时在做三件非常好的事情:
| 归档时间: |
|
| 查看次数: |
80145 次 |
| 最近记录: |