当前位置: 首页 > Linux

Python进阶:设计模式之迭代器模式

时间:2023-04-06 04:39:27 Linux

在软件开发领域,人们经常会用到这个概念——“设计模式”,这是软件设计中的通病。解决方案。在一本圣经的书《设计模式:可复用面向对象软件的基础》(1991,DesignPatterns-ElementsofReusableObject-OrientedSoftware)中,提出了23种设计模式。迭代器模式就是其中之一,广泛应用于各种编程语言中。本文将讲讲Python中的迭代器模式,主要内容:什么是迭代器模式,Python是如何实现迭代器模式的,itertools模块中创建迭代器的方法,迭代器的其他使用场景等,敬请期待与你一起学习进步。1.什么是迭代器模式?维基百科有如下定义:迭代器是最简单和最常见的设计模式之一。它允许用户通过特定的接口访问容器中的每个元素,而无需了解底层实现。——维基百科简单来说,迭代器模式就是一种通用的可以遍历容器类型(如序列类型、集合类型等)的实现。使用迭代器模式,不需要关心遍历的具体对象(如字符串、列表、字典等),也不需要关心遍历的实现算法。它关心的是从容器中遍历/获取元素的结果。根据遍历方式,迭代器可以分为内部迭代器和外部迭代器。它们的区别在于执行迭代动作和保持迭代状态的区别。一般来说,迭代器是一次性的。经过一轮迭代后,再次迭代将得不到任何元素。2.Python的迭代器模式由于迭代器模式的使用实在是太普遍了,所以大多数编程语言都是针对常见的容器类型来实现的,比如Java中的Collection、List、Set、Map等。在Java中使用迭代器遍历List可以这样写:Listlist=newArrayList<>();Iteratoriterator=list.iterator();while(iterator.hasNext()){System。出去。println(iterator.next());}ArrayList类通过自身的iterator()方法获取一个iterator迭代器,然后通过iterator实例实现遍历过程。当然,Python也应用了迭代器模式,只是其实现思路与上面的例子不同。首先,Python认为遍历容器类型不需要迭代器,所以设计了可迭代对象。list=[1,2,3,4]foriinlist:print(i,end="")#1234foriinlist:print(i,end="")#1234Example列表in是一个可迭代对象(Iterable),但不是迭代器(虽然底层实现中使用了迭代器的部分思想)。Python抓住了迭代器模式的本质,即“迭代”,并赋予了它很高的地位。这样设计的好处是显而易见的:(1)写法简单,用意直白;(2)可重复迭代可以避免一次性迭代器的缺陷;(3)无需创建迭代器,减少开销。可迭代对象可以看作是广义迭代器。同时,Python还设计了广义的窄迭代器。list=[1,2,3,4]it=iter(list)foriinit:print(i,end="")#1234foriinit:print(i,end="")#上例中的iter()方法将可迭代对象变成迭代器。从输出可以看出,这个迭代器的迭代过程是一次性的。从这个角度来看,Python其实是将“迭代器模式”拆分成两种来实现的:一种是可迭代的思想,在容器类对象中广泛种植,让它们都可迭代;另一个是迭代器,一个特殊的可迭代对象,承担普通迭代器特有的迭代任务。同时,它还提供了一种将可迭代对象转换为迭代器的简便方法。这种安排确实最大限度地提高了迭代器模式的有效性。(更多可迭代对象和迭代器的区别,以及它们的实现原理,请参考《Python进阶:迭代器与迭代器切片》)3.创建迭代器迭代器的创建有以下几种方式:(1)iter()方法,将一个可迭代对象转换为(2)__iter__()和__next__()魔术方法,定义类来实现这两个魔术方法;(3)itertools模块,使用内置模块生成迭代器;(4)其他创建方法,如zip()、map()、enumerate()等。四种方法中的每一种都有其应用的地方。本节重点介绍itertools模块。它可以创建三种类型的迭代器:无限迭代器、有限迭代器和复合迭代器。3.1无限迭代器count(start=0,step=1):创建一个无限整数迭代器,从start(默认值0)开始,以step(默认值1)为步长。cycle(iterable):对可迭代对象的元素重复执行循环。repeat(object[,times]):重复生成对象直到无穷大,或者直到给定的次数。importitertoolsco=itertools.count()cy=itertools.cycle('ABC')re=itertools.repeat('A',30)#注意:请单独执行;下面的写法不加终止判断,只按Ctrl+C退出forninco:print(n,end="")#01234......fornincy:print(n,end="")#ABCABCAB......forninre:print(n,end="")#AAAAAAAA....(30)3.2以上有限迭代器的方法,比较常用的一个是:chain()将多个可迭代对象(可以是不同类型)组合成一个大型迭代器;compress()方法根据true和false过滤器过滤元素;groupby()在迭代器中挑选出相邻的重复元素,并将它们放在一起;islice()方法返回一个迭代器切片(见《Python进阶:迭代器与迭代器切片》);tee()方法基于可迭代对象创建n(默认2)个迭代器副本。forcinitertools.chain('ABC',[1,2,3]):print(c,end="")#outputresult:ABC123forcinitertools.compress('ABCDEF',[1,1,0,1,0,1]):print(c,end="")#输出结果:ABDFforkey,groupinitertools.groupby('aaabbbaaccd'):print(key,':',list(group))#输出结果:a:['a','a','a']b:['b','b','b']a:['a','a']c:['c','c']d:['d']itertools.tee('abc',3)#outputresult:(,,)3.3组合迭代器product():求解多个可迭代对象的笛卡尔积。permutations():解决可迭代元素的完整排列。combinations():解决可迭代元素的组合。foriinitertools.product('ABC',[1,2]):print(i,end="")#输出结果:('A',1)('A',2)('B',1)('B',2)('C',1)('C',2)foriinitertools.permutations('ABC',2):print(i,end="")#输出结果:('A','B')('A','C')('B','A')('B','C')('C','A')('C','B')foriinitertools.combinations('ABC',2):print(i,end="")#outputresult:('A','B')('A','C')('B','C')foriinitertools.combinations('ABCD',3):print(i,end="")#outputresult:('A','B','C')('A','B','D')('A','C','D')('B','C','D')4.使用强大的内置迭代器方法iteratormodeScenarios太常见了,Python也为迭代器的顺利使用提供了很多方便的条件。本节将介绍几个相关的内置方法。这些方法很常用也很强大,是进阶Python必备的。4.1zip()方法zip()方法可以同时迭代多个序列,每个序列取一个元素生成一个可以返回元组的迭代器。该迭代器的长度与较短序列的长度一致。如果要生成更长序列的长度,则需要使用itertools模块的zip_longest()方法。importitertoolsa=[1,2,3]b=['w','x','y','z']foriinzip(a,b):print(i,end="")#(1,'w')(2,'x')(3,'y')#空值用Noneforiinitertools.zip_longest(a,b):print(i,end="")#(1,'w')(2,'x')(3,'y')(None,'z')4.2enumerate()方法enumerate()方法接收一个序列类型参数并生成一个迭代器,它可以返回一个元组,元组内容为下标及其对应的元素值。它还可以接收一个可选参数,指定下标的起始值,默认为0。注:众所周知,Python中序列的索引值是从0开始的,但是enumerate()可以达到改变的效果起始索引值。seasons=['Spring','Summer','Fall','Winter']foriinenumerate(seasons):print(i,end="")#Outputresult:(0,'Spring')(1,'夏季')(2,'秋季')(3,'冬季')foriinenumerate(seasons,start=7):print(i,end="")#Outputresult:(7,'春季')(8,'Summer')(9,'Fall')(10,'Winter')4.3map()方法map()方法的参数是一个函数和一个或多个可迭代对象,它将迭代对象中的元素of映射到函数,然后迭代运行函数,返回的结果也是一个迭代器。当存在多个可迭代对象参数时,迭代长度等于较短对象的长度。defsquare(x):returnx**2l=map(square,[1,2,3,4,5])print(list(l))#输出结果:[1,4,9,16,25]m=map(lambdax,y:x+y,[1,3,5,7,9],[2,4,6,8,10,2])print(list(m))#输出结果:[3,7,11,15,19]4.4filter()方法filter()方法的参数是一个判断函数和一个可迭代对象,遍历可迭代对象执行判断函数,过滤判断为的元素True,与它相反,如果想保留判断为False的元素,可以使用itertoole模块的filterfalse()方法。importitertoolsfi=filter(lambdax:x%2,range(10))ff=itertools.filterfalse(lambdax:x%2,range(10))foriinfi:print(i,end="")#Outputresult:13579foriinff:print(i,end="")#Outputresult:024685.总结迭代器模式几乎是23种设计模式中最常用的设计模式。本文主要介绍Python如何使用迭代器模式,并介绍了itertools模块中18种生成迭代器的方法,以及5种内置的生成迭代器的方法。相关链接:itertools模块文档:http://t.cn/R6cGtfwPython进阶:迭代器与迭代器切片进阶Python:切片高级特性全面解读!---------------本文首发于微信公众号【蟒猫】,后台回复“爱学习”,送20+精选e-免费书籍。