抽象类在python中的库是abc,它包含的方法有:
ABC
ABCMeta
abstractmethod
abstractclassmethod
abstractstaticmethod
abstractproperty
具体解释可以查看python手册(例子中的code都是基于python3.7实现,python 2.中的写法不一样)
class Super:
def method(self):
print("in Super.method")
def delegate(self):
print("Super.delegate")
self.action()
class Provider(Super):
def action(self):
print("in Provider.action")
X=Provider()
X.delegate()
Y=Super()
print("*"*50)
Y.delegate()
output:
Super.delegate
in Provider.action
**************************************************
Super.delegate
Traceback (most recent call last):
File "C:/Users/yantaozh/AppData/Local/Programs/Python/Python37/try8.py", line 14, in
Y.delegate()
File "C:/Users/yantaozh/AppData/Local/Programs/Python/Python37/try8.py", line 6, in delegate
self.action()
AttributeError: 'Super' object has no attribute 'action'
注意上面的例子中Provider 实例调用了delegate方法,此时会有两个搜索:
from abc import ABC,abstractmethod
class Super(ABC):
def method(self):
print("in Super.method")
def delegate(self):
print("Super.delegate")
self.action()
@abstractmethod
def action(self):
pass
class Provider(Super):
def action(self):
print("in Provider.action")
X=Provider()
X.delegate()
Y=Super()
print("*"*50)
Y.delegate()
output:
Super.delegate
in Provider.action
Traceback (most recent call last):
File "C:/Users/yantaozh/AppData/Local/Programs/Python/Python37/try8.py", line 16, in
Y=Super()
TypeError: Can't instantiate abstract class Super with abstract methods action
>>>
此时我们使用@abstractmethod 内置装饰器来装饰action方法。
通过使用抽象超类时,我们发现当实例化抽象超类的时候会出现异常,此时我们需要记住抽象超类的一个重要属性:
抽象超类不能实例化(因为有未实现的方法),继承了抽象超类的子类必须全部实现被抽象化(@abstractmethod)的方法后才能实例化。
from abc import ABCMeta, abstractclassmethod
class Decorator(metaclass=ABCMeta):
""" Acts as a base class for all decorators """
def __init__(self):
self.method = None
print("init")
def __call__(self, method):
print("call")
self.method = method
print(self.method.__name__)
return self.call
@abstractclassmethod # == @classmethod @abstractmethod
def call(self, *args, **kwargs):
print(2)
return self.method(*args, **kwargs)
class MakeBold(Decorator):
def call(self):
print(4)
return "" + self.method() + ""
class MakeItalic(Decorator):
def call(self):
return "" + self.method() + ""
print("*"*50)
@MakeBold()
@MakeItalic()
def say():
return "Hello"
print(say())
output:
**************************************************
init
init
call
say
call
call
4
Hello
这里的@abstractclassmethod 来装饰一个函数call,通过子类中实现call函数来实现装饰器。
在子类中的call(self)的第一个参数应为cls,但是在这个例子中method 是属于实例的属性,所以在这里通过self来传递为call的第一个参数。在继承的类中重新定义了此函数,需要通过self
这里的装饰器可以==say=MakeBold()(MakeItalic()(say)),say()
from abc import ABC ,abstractmethod ,abstractclassmethod,abstractstaticmethod,abstractproperty
class Base(ABC):
def __init__(self):
self.value = 'Spam'
#@property
#@abstractmethod
@abstractproperty
def x(self):
pass
class Sub1(Base):
def __init__(self):
self._x='ham'
@property
def x(self):
return self._x
ins=Sub1()
print(ins.x)
2.-read-write
from abc import ABC ,abstractmethod ,abstractclassmethod,abstractstaticmethod,abstractproperty
class Base(ABC):
def __init__(self):
self.value = 'Spam'
#@property
#@abstractmethod
@abstractproperty
def x(self):
pass
@x.setter
#@abstractmethod
def x(self,value):
pass
class Sub1(Base):
def __init__(self):
self._x='ham'
@property
def x(self):
return self._x
@x.setter
def x(self,value):
self._x=value
ins=Sub1()
print(ins.x)
ins.x=6
print(ins.x)
3.单独修饰set 时
from abc import ABC ,abstractmethod ,abstractclassmethod,abstractstaticmethod,abstractproperty
class Base(ABC):
def __init__(self):
self._x = 'Spam'
@property
#@abstractmethod
#@abstractproperty
def x(self):
return self._x
@x.setter
@abstractmethod
def x(self,value):
pass
class Sub1(Base):
@Base.x.setter
def x(self,value):
self._x=value
ins=Sub1()
print(ins.x)
ins.x=6
print(ins.x)
from abc import ABC ,abstractmethod ,abstractclassmethod,abstractstaticmethod,abstractproperty
class Base(ABC):
@abstractmethod
def method_1(self):
print("Base method_1")
def method_2(self):
print("Base method_2")
class Sub1:
def method_2(self):
print("Sub1 method_2")
class Sub2(Base):
def method_1(self,a='None'):
print("Sub2 method_1")
pass
Base.register(Sub1)
print(issubclass(Sub1,Base))
i_sub1=Sub1()
i_sub1.method_2()
i_sub2=Sub2()
i_sub2.method_1()
output:
True
Sub1 method_2
Sub2 method_1
这里的register将Sub2变成了Base的一个虚拟子类,此时在Sub2中不需要定义抽象方法也能实例化。
这章中的所有的抽象方法的重写,不仅可以重写内容,参数也可以改变