python 抽象基类(abc)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python 抽象基类(abc)相关的知识,希望对你有一定的参考价值。

设置ABCMeta元类

  抽象类是一类用于继承,但是无需实现具体方法的类,它会创建一些子类必须实现的方法签名。抽象类在定义和强制类抽象方面非常有用,它类似于其他变成语言里面的接口概念,无需实现具体方法。

  从概念上来讲,有一种实现抽象类的方式是对类方法进行存根,然后在类方法被访问的时候直接抛出NotImplementedError异常。这样可以防止子类在没有重写类方法之前直接访问父类的类方法。

像这样:

class Fruit:
    
    def check_ripeness(self):
        raise NotImplementedError("check_ripeness method not implemented!")


class Apple(Fruit):
    pass


a = Apple()
a.check_ripeness() # raises NotImplementedError

  以这种方式创建抽象类可以防止不恰当的使用没有被重写的类方法,当然我们鼓励在子类中定义这些抽象类方法,但却不强制定义。利用abc模块可以防止子类在没有成功地重写父类及其祖先类中抽象类方法之前被实例化。

from abc import ABCMeta

class AbstractClass(object):
    # metaclass 属性必须要设置成类属性 
    __metaclass__ = ABCMeta

   # abstractmethod装饰器, 用来注册该方法为未绑定方法
   @abstractmethod 
   def virtual_method_subclasses_must_define(self):
       # 可以直接不写,也可以提供基础的实现
       # 注意,通常来说,如果不写的话,它会隐式的返回None,
       # 但是通过这样注册的话,它不会强制返回None

  现在就可以简化子类和重写抽象类方法了:

class Subclass(AbstractClass):
    def virtual_method_subclasses_must_define(self):
        return whatever

为什么要使用ABCMeta和abstractmethod,如何使用它们

  抽象基类(ABCs) 强制派生类实现基类中的特定方法。

  为了理解它是如何工作的以及为什么要使用它,我们举个例子来看一下。比如说,我们有一个基类 "MontyPython",里面有两个方法(joke和punchline)必须要在所有的派生类中实现:

class MontyPython:
    def joke(self):
        raise NotImplementedError()

    def punchline(self):
        raise NotImplementedError()

class ArgumentClinic(MontyPython):
    def joke(self):
        return "Hahahahahah"

  当我们实例化出一个对象,并且调用它的这两个方法,在调用punchline的时候会报错:

>>> sketch = ArgumentClinic() 
 >>> sketch.punchline() 
NotImplementedError 

  但是,我们还是可以正常的实例化ArgumentClinic类,并不会出现任何报错。事实上,只有在我们访问punchline()方法的时候才会报错。

  如果使用抽象基类(ABC)模块就不会出现这种问题。通过下面的例子我们来看一下它是如何工作的:

from abc import ABCMeta, abstractmethod

class MontyPython(metaclass=ABCMeta):
    @abstractmethod
    def joke(self):
        pass

    @abstractmethod
    def punchline(self):
        pass

class ArgumentClinic(MontyPython):
    def joke(self):
        return "Hahahahahah"

  现在当我们再实例化这个不完整的类的时候,它马上就会报TypeErrors的错误!

>>> c = ArgumentClinic()
TypeError:
"Can‘t instantiate abstract class ArgumentClinic with abstract methods punchline"

  这种情况下,我们可以通过在子类中实现这两个抽象类都TypeErrors的错误。

class ArgumentClinic(MontyPython):
    def joke(self):
        return "Hahahahahah"

    def punchline(self):
        return "Send in the constable!"

  现在,你就可以正常的实例化ArgumentClinic类了。

以上是关于python 抽象基类(abc)的主要内容,如果未能解决你的问题,请参考以下文章

python 抽象基类(abc)

使用接口/抽象基类是pythonic吗?

python的接口和抽象类

Python2和Python3中@abstractmethod的用法

Python为什么要用抽象类(abc模块)?

python abc模块