Python系列 64 抽象基类

抽象基类

接口(interface)和抽象基类(abstract base class)是非常相似的,Python中并未提供真正意义上的接口,但是提供了抽象基类的使用。

它们的作用在于:

  • 约束子类实现,子类必须实现抽象基类中的某一个方法才能被实例化,否则将不可被实例化

举个例子,羊(Sheep)和狼(Wolf)都属于哺乳类(Breastfeeding),那么它们都至少具有1个方法名为哺乳(feeding),如果没有该方法,则该类不能被实例化。

其实说白了,抽象基类的作用就是规范子类实现,所以:

  • 抽象基类仅用于被继承,不必对其进行实例化
  • 抽象基类内部方法不必实现

abc

Python中用abc模块定义抽象基类,只需要将抽象基类的metaclass=abc.ABCMeta即可。

除此之外,它还提供了3个装饰器:

  • abc.abstractclassmethod:抽象类方法
  • abc.abstractstaticmethod:抽象静态方法
  • abc.abstractmethod:抽象实例方法

代码示例如下:

import abc

class Breastfeeding(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def feeding(self):
        pass

class Sheep(Breastfeeding):
    def feeding(self):
        return "sheep feeding"

class Wolf(Breastfeeding):
    pass

if __name__ == "__main__":
    sheepInstance = Sheep()
    print("sheep class instance success!")
    wolfInstance = Wolf()
    
# sheep class instance success!
# TypeError: Can't instantiate abstract class Wolf with abstract methods feeding

这个例子中,羊实现了哺乳的方法,所以实例化成功了,而狼则没有实现哺乳方法,故实例化失败了。

如果有1个狗(Dog)类继承了狼类,那么狗类能否受到抽象基类的影响呢?

答案是不能,抽象基类只能影响其下一代继承类的实现,不能影响其孙系类。

如下所示:

import abc


class Breastfeeding(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def feeding(self):
        pass


class Sheep(Breastfeeding):
    def feeding(self):
        return "sheep feeding"


class Wolf(Breastfeeding):
    def feeding(self):
        return "wolf fedding"


class Dog(Wolf):
    pass


if __name__ == "__main__":
    sheepInstance = Sheep()
    print("sheep class instance success!")
    wolfInstance = Wolf()
    print("wolf class instance success!")
    dogInstance = Dog()
    print("dog class instance success!")

# sheep class instance success!
# wolf class instance success!
# dog class instance success!

继承约束

通过继承,也能进行子类的行为约束,但是常规手段不能禁止其实例化。

如下所示,狼类没有实现哺乳方法,依然实例化成功了,但是不能调用哺乳方法:

class Breastfeeding:
    def feeding(self):
        raise AssertionError("%s must implement method feeding" %
                             (self.__class__.__name__))


class Sheep(Breastfeeding):
    def feeding(self):
        return "sheep feeding"


class Wolf(Breastfeeding):
    pass


if __name__ == "__main__":
    sheepInstance = Sheep()
    print("sheep class instance success!")
    print(sheepInstance.feeding())
    wolfInstance = Wolf()
    print("wolf class instance success!")
    print(wolfInstance.feeding())

# sheep class instance success!
# sheep feeding
# wolf class instance success!
# AssertionError: Wolf must implement method feeding

上面这种方式在很多框架中也被经常使用到,但如果你想实现和ABCMeta同样的效果,可以覆写基类的__new__()方法,如下所示:

class Breastfeeding:
    def __new__(cls) -> object:
        for attr in Breastfeeding.__dict__:
            if attr.startswith("__"):
                continue
            if attr not in cls.__dict__:
                raise TypeError("Can't instantiate abstract class %s with abstract methods %s" %
                                     (cls.__name__, attr))
        return super(Breastfeeding, cls).__new__(cls)

    def feeding(self):
        pass


class Sheep(Breastfeeding):
    def feeding(self):
        return "sheep feeding"


class Wolf(Breastfeeding):
    pass


if __name__ == "__main__":
    sheepInstance = Sheep()
    print("sheep class instance success!")
    print(sheepInstance.feeding())
    wolfInstance = Wolf()
    print("wolf class instance success!")
    print(wolfInstance.feeding())

# sheep class instance success!
# sheep feeding
# TypeError: Can't instantiate abstract class Wolf with abstract methods feeding
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值