python基础第十九课--OOP定义一个接口或抽象基类(小白piao分享)

抽象基类:

    1、核心特征:
         抽象基类的核心是不能直接进行实例化,如果尝试对抽象基类进行实例化,将会得到如下的结果:

from abc import ABCMeta,abstractmethod
class Istream(metaclass=ABCMeta):
    @abstractmethod
    def read(self,maxbytes = -1):
        pass
    @abstractmethod
    def write(self):
        pass

io = Istream()
#TypeError: Can't instantiate abstract class Istream with abstract methods read, write

    2、功能:
         可以在此之上进行类型检查,并确保在子类中实现特定的办法。用来给其他类当做基类使用,这些子类需要实现基类中要求的那些方法。换句话说,就是强制规定所需的编程接口。
         如果子类并未实现抽象基类中提及的所有方法,则会出现如下问题:

from abc import ABCMeta,abstractmethod
class Istream(metaclass=ABCMeta):
    @abstractmethod
    def read(self,maxbytes = -1):
        pass
    @abstractmethod
    def write(self):
        pass
#io = Istream()#TypeError: Can't instantiate abstract class Istream with abstract methods read, write

class IoMethod(Istream):
    def read(self,maxbytes = -1):
        print('1')

io = IoMethod()
#TypeError: Can't instantiate abstract class IoMethod with abstract methods write
#报错说白了就是说基类中的write方法没有被重写!如果连read都不写只写一个pass,那就以此类推会报错:
'''
class IoMethod(Istream):
    pass
'''
#TypeError: Can't instantiate abstract class IoMethod with abstract methods read,write

         产生上述问题的原因也很简单,子类会继承父类的方法,但是由于父类中的方法为抽象方法在子类中未重写,所以这也是可以理解的。
         上述还有一个问题:如果抽象类中假如说小白将一个重整方法__write()添加在其中会怎样?如下:

from abc import ABCMeta,abstractmethod
class Istream(metaclass=ABCMeta):
    @abstractmethod
    def read(self,maxbytes = -1):
        pass
    @abstractmethod
    def __write(self):
        pass

#io = Istream()#TypeError: Can't instantiate abstract class Istream with abstract methods read, write

class IoMethod(Istream):
    def read(self,maxbytes = -1):
        print('1')
    def __write(self):#注意这里!!!这是一个基类中的重整方法(私有方法)
        print('2')
io = IoMethod()
#请仔细看下报错原因:
#TypeError: Can't instantiate abstract class IoMethod with abstract methods _Istream__write

         所以,这里怎么办呢?有同学会说,为这个私有方法再设计一个get方法:

from abc import ABCMeta,abstractmethod
class Istream(metaclass=ABCMeta):
    @abstractmethod
    def read(self,maxbytes = -1):
        pass
    @abstractmethod
    def __write(self):
        pass
    @abstractmethod
    def get_write(self):
        self.__write()

         这样就可以吗?答案是不行:因为抽象基类的所有方法都需要在子类中实现,没办法逃避只设计get不管__write(),换句话说,两种方法都得设计,另外:你在抽象类中如上写get方法,在子类中还是得重写这个方法,所以基类中的self.__write没有任何作用。那如下这样是否可以:

from abc import ABCMeta,abstractmethod
class Istream(metaclass=ABCMeta):
    @abstractmethod
    def read(self,maxbytes = -1):
        pass
    @abstractmethod
    def __write(self):
        pass
	#注意这行没有abs装饰器了
    def get_write(self):
        self.__write()

         这样想问题同样片面了,__write()还是没有定义啊。那怎么办呢?很多同学到这里就想着放一放再说了,可是,一鼓作气打下来才是学习的必经之路。

         不妨试试这样是否可以:

from abc import ABCMeta,abstractmethod
class Istream(metaclass=ABCMeta):
    @abstractmethod
    def read(self,maxbytes = -1):
        pass
    @abstractmethod
    def __write(self):
        pass

class IoMethod(Istream):
    def read(self,maxbytes = -1):
        print('1')
    def _Istream__write(self):#这样做并不安全,是代码健壮性非常差,非常脆弱的代码结构。
        print('hello')
io = IoMethod()
io._Istream__write()# 打印了hello,并且没有了异常

         有些好问的同学可能又会问道,那怎么证明这个_Istream__write()就是抽象基类的方法呢?万一是自己类中定义的呢?这个问题显而易见,如果是自己类中重新定义的,那么父类(抽象基类)中的__write()你重写了么?如果没有重写?为什么不会报异常出来呢?咱们很早就说过了,抽象类中的所有方法都是需要在子类中重写的。
         但是上过课的同学(有需要的同学,请联系小白piao。)知道,这个东西这样子做,真的好吗?真的安全吗?答案当然是不安全的,所以当我们在设计应用层而非底层的类时,尽量不要在抽象类中出现私有(名称重整)方法

         上文提到,抽象基类是为了强制规定所需的接口的。有些同学会问:那么在其子类中是否允许定义基类中没有的方法呢?

from abc import ABCMeta,abstractmethod
class Istream(metaclass=ABCMeta):
    @abstractmethod
    def read(self,maxbytes = -1):
        pass
    @abstractmethod
    def write(self):
        pass

class IoMethod(Istream):
    def read(self,maxbytes = -1):
        print('1')
    def write(self):
        print('2')
    def serialsize(self):
        pass

io = IoMethod()

         上边不会报错,证明可以再子类中扩充其他方法,所以,这个概念的意思是:必须要定义抽象基类中的所有方法,但是可以扩展其他方法。换个角度,这个问题其实有点幼稚,仔细想想,如果子类只能写抽象基类中有的方法,那么为何还需要定义抽象基类呢?子类只是定义了父类的方法。这里注意,重点是为了为子类限定一些必须定义的接口。

    3、讨论:
        抽象基类允许其他类向其注册,然后实现所需要的接口:

class Istream(metaclass=ABCMeta):
    @abstractmethod
    def read(self,maxbytes = -1):
        pass
    @abstractmethod
    def write(self):
        pass
        
class PrtMethod:
    def prtInfo(self):
        print(self.__dict__)

Istream.register(PrtMethod)
pt = PrtMethod()
print(isinstance(pt,Istream))#True
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白piao

创作不易,支持一下!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值