抽象方法: 定义在基类中的方法, 但却没有任何实现, 任何继承这个基类的子类都必须实现这个方法, 否则会报错
# 实现一个抽象方法最简单的方法--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'