当前位置: 首页 > 科技观察

Python抽象基类的定义和使用

时间:2023-03-12 20:14:33 科技观察

我们在写Python的时候基本上不需要自己创建抽象基类,而是使用ducktyping来解决大部分问题。《流畅的Python》作者用了15年的Python,却只在项目中创建了一个抽象基类。通常,我们创建现有抽象基类的子类,或使用现有的抽象基类注册。这篇文章的意义在于理解抽象基类的定义和使用,可以帮助我们理解抽象基类是如何实现的,为我们以后学习后端语言(如Java、Golang)打下基础.毕竟,抽象基类是编程语言的通用设计。定义抽象基类的子类首先回顾一下什么是抽象基类:Python的抽象基类是指必须允许继承它的子类实现它所需要的抽象方法的类。以下代码定义了抽象基类collections.MutableSequence的子类:(2,11)]+list('JQKA')suits='spadesdiamondsclubhearts'.split()def__init__(self):self._cards=[Card(rank,suit)forsuitinself.suitsforrankinself.ranks]def__len__(self):returnlen(self._cards)def__getitem__(self,position):returnself._cards[position]def__setitem__(self,position,value):#<1>self._cards[position]=valuedef__delitem__(self,position):#<2>自我。_cards[position]definsert(self,position,value):#<3>self._cards.insert(position,value)通过抽象基类collections.MutableSequence源码:可以发现它有三个抽象方法__setitem__,__delitem__,insert,所以FrenchDeck2类必须实现它们。对于append、extend、pop等其他非抽象方法,可以直接继承,无需实现。请注意,Python只会在运行时实例化FrenchDeck2类时实际检查抽象方法的实现。如果没有实现,会抛出TypeError异常,提示Can'tinstantiateabstractclass之类的。标准库中的抽象基类要看哪些抽象基类可以使用,我们可以看一下标准库。collections.abccollections.abc的抽象基类如下图所示:三个抽象基类Iterable、Container、Sized是最基本的类,每个集合都继承这三个抽象基类。Itearble通过__iter__方法支持迭代。Container通过__contains__方法支持in运算符。Sized通过__len__方法支持len()函数。Sequence、Mapping和Set是不可变的集合类型,每个类型都有可变的子类。MappingView.items()、.keys()和.values()返回的对象分别是ItemsView、KeysView和ValuesView的实例。Callable和Hashable为内置函数isinstance提供支持,以确定一个对象是否可以被调用或散列。迭代器迭代器。数的抽象基类如下:NumberComplexRealRationalIntegral这个叫做数塔,上面是超类,下面是子类。例如,使用isinstance(x,numbers.Integral)检查一个数是否为整数,这样代码就可以接受int,bool(int的子类),或者使用isinstance(x,numbers.Real)检查浮点数数字,以便代码可以接受bool、int、float、fractions.Fraction。在此摘要中可以跳过定义抽象基类。但是,了解抽象基类的定义有助于阅读标准库和其他包中抽象基类的源代码。抽象基类的示例代码如下:#BEGINTOMBOLA_ABCimportabcclassTombola(abc.ABC):#<1>@abc.abstractmethoddefload(self,iterable):#<2>"""Additemsfromaniterable."""@abc.abstractmethoddefpick(self):#<3>"""Removeitemrandom,returningit.Thismethodshouldraise`LookupError`whentheinstanceisempty."""defloaded(self):#<4>"""如果至少有1个项目,则返回`True`,否则返回`False`。""returnbool(self.inspect())#<5>definspect(self):"""Returnasortedtuplewiththeitemscurrentlyinside."""items=[]whileTrue:#<6>try:items.append(self.pick())exceptLookupError:breakself.load(items)#<7>returntuple(sorted(items))#ENDTOMBOLA_ABC重点:继承abc.ABC使用@abc.abstractmethod装饰器标记抽象方法抽象基类也可以包含普通方法abstract的子类基类必须重写抽象方法(普通方法不能重写),可以使用super()函数调用抽象方法为其添加功能,而不是实现它从头开始??。看whitegoose类型的定义,whitegoose类型的定义有点难理解。如果了解虚子类,可以加快对白鹅类型的理解。虚子类不是抽象基类的真正子类,而是注册在抽象基类上的子类,这样Python就不会做强制检查。注册方式有两种:register方式Python3.3以前只能使用register方式,例如在collections.abc模块的源码中,内置类型tuple、str、range和memoryview被注册为Sequence的虚拟子类:Sequence.register(tuple)Sequence.register(str)Sequence.register(range)Sequence.register(memoryview)register装饰器将TomboList注册为Tombola的虚拟子类:@Tombola.registerclassTomboList(list):...whitegoosetype和ducktype是Python的动态特性。它们的共同点是只要看起来相似,Python就不会做强制检查。鸭子类型是针对普通类的子类,白鹅类型是针对抽象基类的虚子类。按照。参考:《流畅的Python》第11章接口:从协议到抽象基类