Python中的抽象类

抽象方法: 定义在基类中的方法, 但却没有任何实现, 任何继承这个基类的子类都必须实现这个方法, 否则会报错
# 实现一个抽象方法最简单的方法--Python中提供的NotImplementedError异常
class Sheep:

    def get_size(self):
        raise NotImplementedError
s=Sheep()  # 生成一个实例, 注意实例化时, 并没有抛出错误
s.get_size()  # 只有调用该方法时才会抛出错误
# 以上的方法有一个缺点, 就是定义的子类, 只有调用这个方法时才会抛出异常, 要想在类实例化后触发它, 使用Python提供的abc模块
import abc
class Sheep(metaclass=abc.ABCMeta):   
  @abc.abstractmethod
  def get_size(self):
    return

class SheepChild(Sheep):
    pass

do_test = SheepChild()
# 子类未实现get_size()时实例化对象时都会抛出异常
# Can't instantiate abstract class SheepChild with abstract methods get_size
使用register, 注册子类
import abc 
 
class A(metaclass=abc.ABCMeta):
 
  @abc.abstractmethod
  def load(self):
    return
 
  @abc.abstractmethod
  def save(self):
    return

class B():
   
  def load(self):
    return
 
  def save(self):
    return

class C(A):
   
  def load(self):
    return
 
  def save(self):
    return
    
A.register(B)

if __name__ == '__main__':
  print(issubclass(B, A))   # True
  print(isinstance(B(), A))  # True
  for sc in A.__subclasses__():
  # 如果使用继承的方式会找出所有的具体类, 用register的方式注册子类, 则不会被找出
    print(sc.__name__)
使用__subclasshook__

只要抽象类中定义了__subclasshook__方法之后, 如果具体类实现了与抽象类中同名的方法, 那么这个具体类就是该抽象类的子类, 并且这个具体类创建的实例也是这个抽象类的对象

import abc

class A(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def say(self):
        return 'say yeah'

    @classmethod
    def __subclasshook__(cls, C):
        print(C)
        if cls is A:
            if any("say" in B.__dict__ for B in C.__mro__):
                return True
        return NotImplemented
        
class B:
    def say(self):
        return 'hello'

print(issubclass(B, A))
  # True
print(isinstance(B(), A))
  # True
print(B.__dict__)
print(A.__subclasshook__(B))
  # True

不完全的实现: 虽然具体类是抽象类的子类, 但是具体类中并没有实现抽象类中的say方法, 所以抛出异常

class D(A):
	def test(self):
		pass

if __name__ == '__main__':
    print(issubclass(D, A))
      # print True
    print(isinstance(D(), A))
      # raise TypeError
具体类中使用抽象基类

逻辑可以使用, 但是要重写基类的方法, 然后再调用super方法就行

class A(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def retrieve_values(self):
        print('base class reading data')
        
class B(A):
    def retrieve_values(self):
        super(B, self).retrieve_values()
        print('subclass sorting data')

reader = B()
reader.retrieve_values()
# 和非抽象类之间的继承唯一的区别就是, 不能直接通过mro调用父类的方法
# base class reading data
# subclass sorting data
抽象属性
import abc


class A(metaclass=abc.ABCMeta):

    @abc.abstractproperty
    def value(self):
        return 'should never get here.'


class B(A):
    @property
    def value(self):
        return 'concrete property.'


try:
    a = A()
    print('A.value', a.value)

except Exception as err:
    print('Error: ', str(err))


b = B()
print('B.value', b.value)
定义抽象类的读写属性
import abc


class A(metaclass=abc.ABCMeta):

    def value_getter(self):
        return 'Should never see this.'

    def value_setter(self, value):
        return

    value = abc.abstractproperty(value_getter, value_setter)


class B(A):
    @abc.abstractproperty
    def value(self):
        return 'read-only'


class C(A):
    _value = 'default value'

    def value_getter(self):
        return self._value

    def value_setter(self, value):
        self._value = value

    value = property(value_getter, value_setter)


try:
    a = A()
    print(a.value)
except Exception as err:
    print(str(err))


try:
    b = B()
    print(b.value)
except Exception as err:
    print(str(err))


c = C()
print(c.value)


c.value = 'hello'
print(c.value)
# 定义具体类的property时必须与抽象的abstractproperty相同, 如果只覆盖其中一个将不会工作.
使用装饰器的语法来实现读写的抽象属性, 读和写的方法应该相同
import abc


class A(metaclass=abc.ABCMeta):

    @abc.abstractproperty
    def value(self):
        return 'should never see this.'

    @value.setter
    def value(self, _value):
        return


class B(A):
    _value = 'default'

    @property
    def value(self):
        return self._value

    @value.setter
    def value(self, _value):
        self._value = _value


b = B()
print(b.value)
  # print 'default'

b.value = 'hello'
print(b.value)
  # print 'hello'
总结: 抽象类不能实例化对象, 抽象类规定了必须由继承类实现的方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值