这是一个从Python 3.3的 abc 模块中的源代码派生的工作示例:
from abc import ABCMeta
class abstractclassmethod(classmethod):
__isabstractmethod__ = True
def __init__(self, callable):
callable.__isabstractmethod__ = True
super(abstractclassmethod, self).__init__(callable)
class DemoABC:
__Metaclass__ = ABCMeta
@abstractclassmethod
def from_int(cls, n):
return cls()
class DemoConcrete(DemoABC):
@classmethod
def from_int(cls, n):
return cls(2*n)
def __init__(self, n):
print 'Initializing with', n
运行时的外观如下:
>>> d = DemoConcrete(5) # Succeeds by calling a concrete __init__()
Initializing with 5
>>> d = DemoConcrete.from_int(5) # Succeeds by calling a concrete from_int()
Initializing with 10
>>> DemoABC() # Fails because from_int() is abstract
Traceback (most recent call last):
...
TypeError: Can't instantiate abstract class DemoABC with abstract methods from_int
>>> DemoABC.from_int(5) # Fails because from_int() is not implemented
Traceback (most recent call last):
...
TypeError: Can't instantiate abstract class DemoABC with abstract methods from_int
请注意,最后一个示例失败,因为cls()
不会实例化。 ABCMeta 可以防止尚未定义所有必需抽象方法的类的过早实例化。
调用from_int() 抽象类方法时触发失败的另一种方法是使它引发异常:
class DemoABC:
__Metaclass__ = ABCMeta
@abstractclassmethod
def from_int(cls, n):
raise NotImplementedError
设计 ABCMeta 会不遗余力防止在未实例化的类上调用任何抽象方法,因此您可以通过调用cls()
类方法(通常是这样做的)或引发NotImplementedError 来触发失败。无论哪种方式,您都会遇到一个不错的干净故障。
可能很想编写一个描述符来拦截对抽象类方法的直接调用,但这与 ABCMeta的 总体设计是 矛盾的 ( ABCMeta的总体设计 是关于在实例化之前检查必需的方法,而不是在调用方法时)。 。