设置ABCMeta元类
抽象类是一类用于继承,但是无需实现具体方法的类,它会创建一些子类必须实现的方法签名。抽象类在定义和强制类抽象方面非常有用,它类似于其他变成语言里面的接口概念,无需实现具体方法。
从概念上来讲,有一种实现抽象类的方式是对类方法进行存根,然后在类方法被访问的时候直接抛出NotImplementedError异常。这样可以防止子类在没有重写类方法之前直接访问父类的类方法。
像这样:
classFruit:defcheck_ripeness(self):raise NotImplementedError("check_ripeness method not implemented!")classApple(Fruit):passa=Apple()
a.check_ripeness()#raises NotImplementedError
以这种方式创建抽象类可以防止不恰当的使用没有被重写的类方法,当然我们鼓励在子类中定义这些抽象类方法,但却不强制定义。利用abc模块可以防止子类在没有成功地重写父类及其祖先类中抽象类方法之前被实例化。
from abc importABCMetaclassAbstractClass(object):#metaclass 属性必须要设置成类属性
__metaclass__ =ABCMeta#abstractmethod装饰器, 用来注册该方法为未绑定方法
@abstractmethoddefvirtual_method_subclasses_must_define(self):#可以直接不写,也可以提供基础的实现
#注意,通常来说,如果不写的话,它会隐式的返回None,
#但是通过这样注册的话,它不会强制返回None
现在就可以简化子类和重写抽象类方法了:
classSubclass(AbstractClass):defvirtual_method_subclasses_must_define(self):return ‘whatever‘
为什么要使用ABCMeta和abstractmethod,如何使用它们
抽象基类(ABCs) 强制派生类实现基类中的特定方法。
为了理解它是如何工作的以及为什么要使用它,我们举个例子来看一下。比如说,我们有一个基类 "MontyPython",里面有两个方法(joke和punchline)必须要在所有的派生类中实现:
classMontyPython:defjoke(self):raiseNotImplementedError()defpunchline(self):raiseNotImplementedError()classArgumentClinic(MontyPython):defjoke(self):return "Hahahahahah"
当我们实例化出一个对象,并且调用它的这两个方法,在调用punchline的时候会报错:
>>> sketch =ArgumentClinic()>>>sketch.punchline()
NotImplementedError
但是,我们还是可以正常的实例化ArgumentClinic类,并不会出现任何报错。事实上,只有在我们访问punchline()方法的时候才会报错。
如果使用抽象基类(ABC)模块就不会出现这种问题。通过下面的例子我们来看一下它是如何工作的:
from abc importABCMeta, abstractmethodclass MontyPython(metaclass=ABCMeta):
@abstractmethoddefjoke(self):pass@abstractmethoddefpunchline(self):pass
classArgumentClinic(MontyPython):defjoke(self):return "Hahahahahah"
现在当我们再实例化这个不完整的类的时候,它马上就会报TypeErrors的错误!
>>> c =ArgumentClinic()
TypeError:"Can‘t instantiate abstract class ArgumentClinic with abstract methods punchline"
这种情况下,我们可以通过在子类中实现这两个抽象类都TypeErrors的错误。
classArgumentClinic(MontyPython):defjoke(self):return "Hahahahahah"
defpunchline(self):return "Send in the constable!"
现在,你就可以正常的实例化ArgumentClinic类了。