[转载] Python进阶:设计模式之迭代器模式

参考链接: Python中的迭代器

在软件开发领域中,人们经常会用到这一个概念——“设计模式”(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<String> list = new ArrayList<>();

Iterator<String> 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)

# 输出结果:(<itertools._tee at 0x1fc72c08108>,

 <itertools._tee at 0x1fc73f91d08>,

 <itertools._tee at 0x1fc73efc248>)

 

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 种生成迭代器的内置方法。 

相关链接: 

itertools模块文档:http://t.cn/R6cGtfw 

Python进阶:迭代器与迭代器切片 

Python进阶:全面解读高级特性之切片! 

----------------- 

本文原创并首发于微信公众号【Python猫】,后台回复“爱学习”,免费获得20+本精选电子书。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/540481.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JavaScript | 如何为变量分配十进制,八进制和十六进制值?

Just like C programming language, we can assign integer value in the different format to the variable. 就像C编程语言一样 &#xff0c;我们可以将不同格式的整数值分配给变量。 Assigning decimal value: It can be assigned simply without using any prefix. 分配十…

路由器DHCP和DHCP中继的配置

路由器 DHCP和DHCP中继的配置 路由器作为DHCP服务器&#xff1a; 1.配置router的地址&#xff1a;Route(config)# hostname gateway (更改主机名字) Gateway(config)# interface gigabitethernet 0/0 …

[转载] 大数据分析Python For循环教程

参考链接&#xff1a; Python中的迭代器函数1 大数据分析Python除了循环遍历列表之外&#xff0c;for循环还有很多其他功能&#xff0c;在现实世界的数据科学工作中&#xff0c;您可能需要将numpy数组和pandas DataFrames用于其他数据结构的循环。 大数据分析Python For循环教…

node.js 爬虫入门总结

node.js爬虫 前端同学可能向来对爬虫不是很感冒&#xff0c;觉得爬虫需要用偏后端的语言&#xff0c;诸如 php &#xff0c; python 等。当然这是在 nodejs 前了&#xff0c;nodejs 的出现&#xff0c;使得 Javascript 也可以用来写爬虫了。由于 nodejs 强大的异步特性&#xf…

数组重复次数最多的元素递归_使用递归计算链接列表中元素的出现次数

数组重复次数最多的元素递归Solution: 解&#xff1a; Required function: 所需功能&#xff1a; func_occurence ( node *temp) //recursive functionInput: 输入&#xff1a; A singly linked list whose address of the first node is stored in a pointer, say head and…

SecureCRT中文乱码解决方法

服务端export LANGzh_CN.UTF-8客户端SecureCRT编码选择UTF-8客户端SecureCRT字体选择新宋体&#xff0c;字符集选择中文总结&#xff1a;客户端和服务端字符编码一致&#xff0c;客户端字体字符集支持转载于:https://blog.51cto.com/leomars/1972669

[转载] Python 迭代器 深入理解 与应用示例

参考链接&#xff1a; Python | 可迭代和迭代器之间的区别 本篇文章简单谈谈可迭代对象&#xff0c;迭代器和生成器之间的关系。 三者简要关系图 可迭代对象与迭代器 刚开始我认为这两者是等同的&#xff0c;但后来发现并不是这样&#xff1b;下面直接抛出结论&#xff1a; 1…

Python程序查找表示O(1)复杂度的数字所需的位数

Problem statement 问题陈述 Find total Number of bits required to represent a number in binary 查找以二进制表示数字所需的总位数 Example 1: 范例1&#xff1a; input : 10output: 4Example 2: 范例2&#xff1a; input : 32output : 6Formula used: 使用的公式&am…

正则split

string content "第1行导入失败&#xff0c;失败原因为&#xff1a; 《加班原因》字段必填";string[] resultString Regex.Split(content, "失败原因为&#xff1a;", RegexOptions.IgnoreCase);foreach (string i in resultString){Console.WriteLine(i…

将八进制数制转换为二进制,十进制和十六进制数制

1)将八进制数制转换为二进制数制 (1) Conversion of Octal Number System to Binary Number System) To convert octal numbers into binary numbers, we can use the relationship between octal and binary numbers. 要将八进制数转换为二进制数&#xff0c;我们可以使用八进…

[转载] Python的生成器

参考链接&#xff1a; Python中的生成器Generator Python的生成器 什么是生成器 创建python迭代器的过程虽然强大&#xff0c;但是很多时候使用不方便。生成器是一个简单的方式来完成迭代。简单来说&#xff0c;Python的生成器是一个返回可以迭代对象的函数。 怎样创建生…

想提高用户访问的响应速度和成功率还不赶快学习CDN

2019独角兽企业重金招聘Python工程师标准>>> 课程介绍 CDN可以将源站内容分发至最接近用户的节点&#xff0c;使用户可就近取得所需内容&#xff0c;提高用户访问的响应速度和成功率。解决因分布、带宽、服务器性能带来的访问延迟问题&#xff0c;适用于站点加速、点…

[转载] python迭代器、生成器和装饰器

参考链接&#xff1a; 有效地在Python中使用迭代 文章目录 生成器生成器表达式(generator expression)通过使用yield关键字定义生成器并行前戏高潮 迭代器迭代器概述iter()函数 创建迭代器创建一个迭代器(类)内置迭代器工具count无限迭代器cycle 无限迭代器&#xff0c;从一个…

java中的starts_Java Math类静态double nextAfter(double starts,double direction)示例

java中的starts数学类静态double nextAfter(双向启动&#xff0c;双向) (Math Class static double nextAfter(double starts , double directions) ) This method is available in java.lang package. 此方法在java.lang包中可用。 This method is used to return the double …

Python 核心编程(第二版)——条件和循环

Python 中的 if 子句由三部分组成: 关键字本身&#xff0c;用于判断结果真假的条件表达式&#xff0c; 以及当表达式为真或者非零时执行的代码块。if 语句的语法如下: if expression: expr_true_suite 单个 if 语句可以通过使用布尔操作符 and , or 和 not实现多重判断条件或…

[转载] 【python魔术方法】迭代器(__iter__和__next__)

参考链接&#xff1a; Python __iter __()和__next __()| 将对象转换为迭代器 文章目录 __iter__ 和 __next__真正的迭代器总结 python里面有很多的以__开始和结尾的函数&#xff0c;利用它们可以完成很多复杂的逻辑代码&#xff0c;而且提高了代码的简洁性&#xff0c;本文主…

Silverlight 异步单元测试

Silverlight 中的很多操作都是异步的&#xff0c;很多情况下要求单元测试也是异步的&#xff0c;但是介绍异步单元测试的文档很少。通过对 Silverlight Toolkit 中的 Microsoft.Silverlight.Testing 和 Microsoft.VisualStudio.QualityTools.UnitTesting.Silverlight 这两个文件…

网络拓扑 令牌环网 以太网_以太网连接中网络拓扑的类型及其框架 以太网技术...

网络拓扑 令牌环网 以太网A topology explains how physically the network is designed or what is the structure of the network. These designs are both physical and logical. There are many network topologies 4 like Bus, Star, Ring, and Mesh. But only two types …

Wafer晶圆封装工艺介绍

芯片封装的目的&#xff08;The purpose of chip packaging&#xff09;: 芯片上的IC管芯被切割以进行管芯间连接&#xff0c;通过引线键合连接外部引脚&#xff0c;然后进行成型&#xff0c;以保护电子封装器件免受环境污染&#xff08;水分、温度、污染物等&#xff09;&…

[转载] Python中的解析式和生成器表达式

参考链接&#xff1a; Python | 生成器表达式 解析式和生成器表达式 列表解析List Comprehension 语法 [返回值 for 元素 in 可迭代对象 if 条件]使用中括号[],内部是for循环&#xff0c;if条件语句可选&#xff0c;会返回一个新的列表 列表解析试优点 编译器会优化&…