网易首页 > 网易号 > 正文 申请入驻

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

0
分享至

在软件开发领域中,人们经常会用到这一个概念——“设计模式”(design pattern),它是一种针对软件设计的共性问题而提出的解决方案。在一本圣经级的书籍《设计模式:可复用面向对象软件的基础》(1991年,Design Patterns - Elements of Reusable Object-Oriented Software)中,它提出了23种设计模式。迭代器模式就是其中的一种,在各种编程语言中都得到了广泛的应用。

本文将谈谈 Python 中的迭代器模式,主要内容:什么是迭代器模式、Python 如何实现迭代器模式、itertools 模块创建迭代器的方法、其它运用迭代器的场景等等,期待与你共同学习进步。

1、什么是迭代器模式?

维基百科有如下定义:

迭代器是一种最简单也最常见的设计模式。它可以让用户透过特定的接口巡访容器中的每一个元素而不用了解底层的实现。——维基百科

简单地说,迭代器模式就是一种通用性的可以遍历容器类型(如序列类型、集合类型等)的实现方式。使用迭代器模式,可以不关心遍历的对象具体是什么(如字符串、列表、字典等等),也不需要关心遍历的实现算法是什么,它关心的是从容器中遍历/取出元素的结果。

按遍历方式划分,迭代器可分为内部迭代器与外部迭代器,它们的区别在于执行迭代动作与维持迭代状态的不同。

通常而言,迭代器是一次性的,当迭代过一轮后,再次迭代将获取不到元素。

2、Python的迭代器模式

由于迭代器模式的使用太常见了,所以大多数编程语言都给常见的容器类型实现了它,例如 Java 中的 Collection,List、Set、Map等。在 Java 中使用迭代器遍历 List 可这么写:

List

list = new ArrayList<>();Iterator

iterator = list.iterator();while(iterator.hasNext()){ System.out.println(iterator.next());}

ArrayList 类通过自身的 iterator() 方法获得一个迭代器 iterator,然后由该迭代器实例来落实遍历过程。

Python 当然也应用了迭代器模式,但它的实现思路跟上例却不太一样。

首先,Python 认为遍历容器类型并不一定要用到迭代器,因此设计了可迭代对象。

list = [1,2,3,4]
for i in list:
print(i,end=" ") # 1 2 3 4
for i in list:
print(i,end=" ") # 1 2 3 4

上例中的 list 是可迭代对象(Iterable),但并不是迭代器(虽然在底层实现时用了迭代器的部分思想)。Python 抓住了迭代器模式的本质,即是“迭代”,赋予了它极高的地位。

如此设计的好处显而易见:(1)写法简便,用意直白;(2)可重复迭代,避免一次性迭代器的缺陷;(3)不需要创建迭代器,减少开销。

可迭代对象可看作是广义的迭代器,同时,Python 也设计了普通意义的狭义的迭代器。

list = [1,2,3,4]
it = iter(list)
for i in it:
print(i,end=" ") # 1 2 3 4
for i in it:
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]) :反复生成 object 至无限,或者到给定的 times 次。

import itertools
co = itertools.count()
cy = itertools.cycle('ABC')
re = itertools.repeat('A', 30)
# 注意:请分别执行;以下写法未加终止判断,只能按 Ctrl+C 退出
for n in co:
print(n,end=" ") # 0 1 2 3 4......
for n in cy:
print(n,end=" ") # A B C A B C A B......
for n in re:
print(n,end=" ") # A A A A A A A A....(30个)

3.2 有限迭代器

以上方法,比较常用的有:chain() 将多个可迭代对象(可以是不同类型)连接成一个大迭代器;compress() 方法根据真假过滤器筛选元素;groupby() 把迭代器中相邻的重复元素挑出来放在一起;islice() 方法返回迭代器切片(用法参见《Python进阶:迭代器与迭代器切片》);tee() 方法根据可迭代对象创建 n 个(默认2个)迭代器副本。

for c in itertools.chain('ABC', [1,2,3]):
print(c,end=" ")
# 输出结果:A B C 1 2 3
for c in itertools.compress('ABCDEF', [1, 1, 0, 1, 0, 1]):
print(c,end=" ")
# 输出结果:A B D F
for key, group in itertools.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)
# 输出结果:(

,

,

3.3 组合迭代器

product() :求解多个可迭代对象的笛卡尔积。

permutations() :求解可迭代对象的元素的排列。

combinations():求解可迭代对象的元素的组合。

for i in itertools.product('ABC', [1,2]):
print(i, end=" ")
# 输出结果:('A', 1) ('A', 2) ('B', 1) ('B', 2) ('C', 1) ('C', 2)
for i in itertools.permutations('ABC', 2):
print(i, end=" ")
# 输出结果:('A', 'B') ('A', 'C') ('B', 'A') ('B', 'C') ('C', 'A') ('C', 'B')
for i in itertools.combinations('ABC', 2):
print(i, end=" ")
# 输出结果:('A', 'B') ('A', 'C') ('B', 'C')
for i in itertools.combinations('ABCD', 3):
print(i, end=" ")
# 输出结果:('A', 'B', 'C') ('A', 'B', 'D') ('A', 'C', 'D') ('B', 'C', 'D')

4、强大的内置迭代器方法

迭代器模式的使用场景实在太普遍了,而 Python 也为迭代器的顺利使用而提供了很多便利的条件,本节将介绍相关的几个内置方法。这些方法非常常用而且强大,是 Python 进阶的必会内容。

4.1 zip() 方法

zip() 方法可以同时迭代多个序列,并各取一个元素,生成一个可返回元组的迭代器。此迭代器的长度以较短序列的长度保持一致,若想生成较长序列的长度,需要使用 itertools 模块的 zip_longest() 方法。

import itertools
a = [1, 2, 3]
b = ['w', 'x', 'y', 'z']
for i in zip(a,b):
print(i,end=" ") # (1, 'w') (2, 'x') (3, 'y')
# 空缺值以 None 填补
for i in itertools.zip_longest(a,b):
print(i,end=" ") # (1, 'w') (2, 'x') (3, 'y') (None, 'z')

4.2 enumerate() 方法

enumerate() 方法接收一个序列类型参数,生成一个可返回元组的迭代器,元组内容是下标及其对应的元素值。它还可接收一个可选参数,指定下标的起始值,默认是0 。

注意:众所周知,Python 中序列的索引值从 0 开始,但是,enumerate() 可以达到改变起始索引数值的效果。

seasons = ['Spring', 'Summer', 'Fall', 'Winter']
for i in enumerate(seasons):
print(i,end=" ")
#输出结果:(0, 'Spring') (1, 'Summer') (2, 'Fall') (3, 'Winter')
for i in enumerate(seasons, start=7):
print(i,end=" ")
#输出结果:(7, 'Spring') (8, 'Summer') (9, 'Fall') (10, 'Winter')

4.3 map() 方法

map() 方法的参数是一个函数及一个或多个可迭代对象,它会将可迭代对象的元素映射到该函数中,然后迭代地运行该函数,返回结果也是一个迭代器。当存在多个可迭代对象参数时,迭代长度等于较短对象的长度。

def square(x):
return x ** 2
l = map(square, [1, 2, 3, 4, 5])
print(list(l))
# 输出结果:[1, 4, 9, 16, 25]
m = map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10, 2])
print(list(m))
# 输出结果:[3, 7, 11, 15, 19]

4.4 filter() 方法

filter() 方法的参数是一个判断函数及一个可迭代对象,遍历可迭代对象执行判断函数,过滤下判断为True 的元素,与它相对,若想保留判断为 False 的元素,可使用 itertoole 模块的 filterfalse() 方法。

import itertools
fi = filter(lambda x: x%2, range(10))
ff = itertools.filterfalse(lambda x: x%2, range(10))
for i in fi:
print(i,end=" ")
# 输出结果:1 3 5 7 9
for i in ff:
print(i,end=" ")
# 输出结果:0 2 4 6 8

5. 小结

迭代器模式几乎是 23 种设计模式中最常用的设计模式,本文主要介绍了 Python 是如何运用迭代器模式,并介绍了 itertools 模块生成迭代器的 18 种方法,以及 5 种生成迭代器的内置方法。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
当你经常去同一家饭店吃饭,和店老板熟悉起来后产生的一些默契

当你经常去同一家饭店吃饭,和店老板熟悉起来后产生的一些默契

新动察
2024-06-16 11:49:10
苏纳克骨子里还是流淌着三哥的血脉,突然明白为啥不让韩国参会了

苏纳克骨子里还是流淌着三哥的血脉,突然明白为啥不让韩国参会了

芯怡飞
2024-06-17 00:25:38
突发!福建武平县中赤镇求救,整个村通讯中断,整个镇都泡在水里

突发!福建武平县中赤镇求救,整个村通讯中断,整个镇都泡在水里

火山诗话
2024-06-17 06:33:17
智利正式申请加入《区域全面经济伙伴关系协定》

智利正式申请加入《区域全面经济伙伴关系协定》

界面新闻
2024-06-16 07:10:30
北大吴谢宇弑母通灵记录:通灵人自曝与其交流,得知弑母真实动机

北大吴谢宇弑母通灵记录:通灵人自曝与其交流,得知弑母真实动机

古今档案
2024-05-29 18:42:08
新能源车下乡正式启动

新能源车下乡正式启动

电动知家
2024-06-15 13:27:45
二手房太难卖了,某一线城市从1000万降至520万都卖不出去

二手房太难卖了,某一线城市从1000万降至520万都卖不出去

有事问彭叔
2024-06-14 15:16:44
以色列把真主党的2号领导送“走”了

以色列把真主党的2号领导送“走”了

近距离
2024-06-14 19:28:25
毛主席的命令:除大将外,从上将到少校,明年和我一起横渡长江!

毛主席的命令:除大将外,从上将到少校,明年和我一起横渡长江!

陈冠任
2024-06-16 09:02:20
NBA官方更新FMVP排行榜!凯尔特人占据三席,最终归属已有答案

NBA官方更新FMVP排行榜!凯尔特人占据三席,最终归属已有答案

奕辰说球
2024-06-17 11:00:15
姜萍表叔说了一句大实话!以她的家庭学技术更好,上大学未必圆梦

姜萍表叔说了一句大实话!以她的家庭学技术更好,上大学未必圆梦

快乐娱文
2024-06-17 10:33:50
美媒:美国中央司令部宣布,已成功摧毁7台雷达

美媒:美国中央司令部宣布,已成功摧毁7台雷达

新时光点滴
2024-06-17 07:52:17
湖南:小伙捧鲜花表白女技师,做足疗一见钟情,网友:长得很哇塞

湖南:小伙捧鲜花表白女技师,做足疗一见钟情,网友:长得很哇塞

百晓史
2024-06-02 09:09:36
马英九办公室:赖清德倾向寻求战争

马英九办公室:赖清德倾向寻求战争

直新闻
2024-06-16 19:58:35
白酒为什么不能冰镇之后喝?网友:在医院门口喝都赶不上趟

白酒为什么不能冰镇之后喝?网友:在医院门口喝都赶不上趟

奇特短尾矮袋鼠
2024-06-15 14:31:42
中国经济巨大成就的背后:有两个痛点,是什么痛点?

中国经济巨大成就的背后:有两个痛点,是什么痛点?

永不出场的戈多
2024-06-15 07:58:52
笑不活了,新加坡门将桑尼来上海了,我却笑死在网友评论区里

笑不活了,新加坡门将桑尼来上海了,我却笑死在网友评论区里

小豆豆赛事
2024-06-16 23:31:49
真核退役皇马因祸得福,德布劳内告别曼城,冲击金球,与瓜帅闹翻

真核退役皇马因祸得福,德布劳内告别曼城,冲击金球,与瓜帅闹翻

小金体坛大视野
2024-06-16 18:10:20
广州市最大城中村,市政府却不敢拆?原因其实是房价高得离谱!

广州市最大城中村,市政府却不敢拆?原因其实是房价高得离谱!

林子说事
2024-06-17 07:15:09
姆巴佩:我不会去参加奥运会 皇马的立场很明确

姆巴佩:我不会去参加奥运会 皇马的立场很明确

雷速体育
2024-06-17 10:26:10
2024-06-17 13:36:49
科技生活圈
科技生活圈
科技
519文章数 111273关注度
往期回顾 全部

科技要闻

OpenAI可能会迎来重大变化

头条要闻

上市公司原子公司税务被"倒查30年" 税务人士发声

头条要闻

上市公司原子公司税务被"倒查30年" 税务人士发声

体育要闻

豪华阵容,原始战术 英格兰10亿天团就这?

娱乐要闻

上影节红毯:倪妮好松弛,娜扎吸睛

财经要闻

省市级税务人士:目前没有全国性查税

汽车要闻

传奇新篇章 全新一代大众迈腾来了

态度原创

旅游
艺术
房产
手机
公开课

旅游要闻

游客放狗进赛里木湖追天鹅,景区回应!

艺术要闻

穿越时空的艺术:《马可·波罗》AI沉浸影片探索人类文明

房产要闻

强!全国第三!海口房价正在止跌!

手机要闻

骁龙8 Gen3领先版参数曝光!大核主频升级为3.4Ghz

公开课

近视只是视力差?小心并发症

无障碍浏览 进入关怀版