背景:最近在学习python,关于迭代很多教材都没有清晰描述,查找了一些网上的教程,但总感觉思路不够清晰,于是查阅了相关资料,对python中各种迭代现象及相关机制深入理解,理清概念。
什么是迭代:
我们通过顺序、分支(if else)、循环(for while)来控制程序的运行,这被称之为控制流
根据冯诺依曼模型,计算机所作的就是: 输入数据——处理数据——输出数据
我们输入一组数据,需要对其中的每一项进行处理,这就引入了重复操作,不管叫什么,
循环、迭代、递归、编历,都只是对这种重复操作的具体实现。
在编程中语言中,通过for while 来实现对数据的重复操作
python中的迭代现象:
由于for的通用性和迭代现象的存在,python衍生出了大量的基于迭代的概念和for相关的工具
从某种角度看,程序的本质是数据结构+算法,数据结构是核心,数据结构确定了,算法不言
自明。我们来看看python中的数据结构及其与迭代现象的相关性
一.序列类型
序列是元素按照先后顺序排列组成的一组数据
序列的重点是顺序,我们可以给每一个元素建立一个位置(从0开始)(即索引)
1.字符串(str)
a = 'hello world'
a[0] = 'h'
a[0:2] = 'he'
2.列表(list)
b = [1,2,3]
b[0] = 1
b[0:3] = [1,2,3]
3.元组(tuple)
c = (4,5,6)
由于序列具有先后顺序,我们可以对其进行索引、切片
很显然,序列可以迭代的(可迭代对象)
for i in a:
print(i,end='')
输出: hello world
while i
print(a[i],end='')
i+=1
输出:hello world
注意!!虽然for 和 while 输出相同,但是for是通过序列的‘可迭代协议’来运行(序列通过其
可迭代协议创建一个‘迭代器’供for使用)
而 while 是通过序列的索引来进行遍历(序列支持‘序列协议’)
for 比 while 效率要高很多,关于迭代协议和迭代器后面会讲到。
二.映射类型
python中的映射属于一一映射,只有一个映射类型
字典(dict)
字典是支持‘可迭代协议的’,所以可以被for迭代
d = {'a':1,'b':2,'c':3}
for i in d:
print(i,end=' ')
输出:1 2 3
注意!! 只要通过for进行遍历,字典通过‘可迭代协议’生成一个'迭代器',每迭代一次,返回
一个字典的键,然后通过键打印值
三.集合(set)
python中的集合很接近数学意义上的集合
e = {'a',1,0.3}
集合也是支持‘可迭代协议的’,所以for编历时自动生成‘迭代器’,完成迭代
for i in e:
print(i,end=' ')
输出:1 0.3 'a'
注意!!由于集合不是序列,所以生成‘迭代器’时,顺序是随机的,输出会乱序
四.文本文件
没错,文本文件(其实是通过open()返回的对象)也是可迭代对象,它每次返回一行,
支持‘可迭代协议’,自身就是一个‘迭代器’
h.txt
hello
world
with open('h.txt') as f:
for i in f:
print(i,end='')
输出:
hello
world
迭代协议与迭代器
python提供了一个内置函数 dir() 来查看对象的属性和方法,一个对象是否支持迭代协议,是不是迭代器,由这些属性和方法决定。
看一些例子:
dir(str)
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__',
'__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__',
'__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__',
'__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__',
'__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize',
'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find',
'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal',
'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace',
'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans',
'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit',
'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title',
'translate', 'upper', 'zfill']
str(字符串) 含有 __getitem__ 所以支持‘序列协议’
含有 __iter__ 所以支持‘可迭代协议’
dir(dict)
['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__',
'__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__',
'__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__',
'__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__reversed__', '__setattr__', '__setitem__', '__sizeof__', '__str__',
'__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop',
'popitem', 'setdefault', 'update', 'values']
dict(字典) 含有 __getitem__ 所以支持‘序列协议’
含有 __iter__ 所以支持‘可迭代协议’
文件
h.txt
hello
world
f = open('h.txt')
dir(f)
['_CHUNK_SIZE', '__class__', '__del__', '__delattr__', '__dict__', '__dir__',
'__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__',
'__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__',
'__iter__', '__le__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__', '_checkClosed', '_checkReadable', '_checkSeekable',
'_checkWritable', '_finalizing', 'buffer', 'close', 'closed', 'detach',
'encoding', 'errors', 'fileno', 'flush', 'isatty', 'line_buffering', 'mode',
'name', 'newlines', 'read', 'readable', 'readline', 'readlines', 'reconfigure',
'seek', 'seekable', 'tell', 'truncate', 'writable', 'write', 'write_through',
'writelines']
对象f(文件) 含有 __iter__ 所以支持‘可迭代协议’
含有 __next__ 所以支持 next() 方法调用
综上,可以对相关概念下定义:
可迭代对象: 支持__getitem__(序列协议)或 __iter__(可迭代协议)或 (__iter__ 和__next__ )
(next方法不能独立存在,它和可迭代协议是绑定的)
迭代器:支持 __iter__ 和__next__ 的对象(俩者是绑定的)
使用for循环时会自动创建一个迭代器,我们也可以手动创建迭代器:(通过内置函数iter())
g = [1,2,3]
h = iter(g)
next(h)
输出:1
next(h)
输出:2
next(h)
输出:3
next(h)
输出:StopIteration
当迭代器 h 运行到末尾时会显示迭代结束
生成器:
所有生成器都是迭代器,因为生成器支持 __iter__ 和__next__ 。
俩者有微妙的区别。
迭代器用于从已经存在的一组数据中取出元素;而生成器用于“凭空”(根据一定的规则)生成元
素。不过大多数时候都把迭代器和生成器视作同一概念。
有2中方法创建生成器:
1.列表生成式
m = (i**2 for i in range(5))
2.yield 生成器函数
def fun():
for i in range(5):
yield i**2
n = fun()