迭代(Iteration)
当我们使⽤⼀个循环来遍历某个东西时,这就叫⼀个迭代。
可迭代对象(Iterable)
⼀个可迭代对象是Python中任意的对象,只要它定义了可以返回⼀个迭代器的__iter__
⽅法,或者定义了可以⽀持下标索引的__getitem__
⽅法。简单说,⼀个可迭代对象,就是任意的对象,只要它能给我们提供⼀个迭代器。
container__iter__()
返回一个迭代器对象。 该对象需要支持迭代器协议。 如果容器支持不同的迭代类型,则可以提供额外的方法来专门地请求不同迭代类型的迭代器。
迭代器(Iterator)
⼀个迭代器是任意⼀个对象,只要它定义了⼀个next(Python2) 或者__next__
⽅法。
iterator.__next__()
从容器中返回下一项。 如果已经没有项可返回,则会引发 StopIteration
异常。
特点: 节省内存,惰性机制,不能反复, 只能向下执行.
- 迭代器是可迭代的,所有的迭代器都是它们自己的迭代器
- 迭代器没有长度,它们不能被索引
- 可以把迭代器看作是惰性迭代器,它们是一次性使用,这意味着它们只能循环遍历一次。
文件迭代器
#手动遍历
f = open('xxx','r',encoding='utf8')
f.readline() #每次调用readine方法,就会到下一列,最后一行使用得到空字符
#使用f.__next__()可以达到同样的效果,不同的是,已达到最后一行,继续使用__next__会引发StopIteration异常,捕获即可解决。
#文件对象本身就是一个迭代器
#常用for循环迭代,调用内部的__next__
for i f:
xxxxx
列表
列表以及很多其他的内置对象,不是自身的迭代器,所以支持多次打开迭代器。
L = [1,2,3]
L.__next__()
#AttributeError: 'list' object has no attribute '__next__'
lst = [1,2,3]
lst_iter = lst.__iter__()
#while循环+迭代器模拟登录
while True:
try:
i = lst_iter.__next__()
print(i)
except StopIteration:
break
L = [1,2,3]
a = L.__getitem__(2) # 支持下标索引,L[2]
print(a)
# 3
range
内置函数range,返回一个可迭代对象,根据需要产生范围中的数字,而不是在内存中构建一个结果列表
>>> range(0,7)
range(0, 7)
>>> r = range(0,7)
>>> r[3]
3
>>> len(r)
7
>>> list(range(0,7)) #强制转换成列表
[0, 1, 2, 3, 4, 5, 6]
map、zip和filter
map、zip和filter和range不同,它们都是自己的迭代器。range支持len和索引,而它们不支持。
>>> M
<map object at 0x0401A870>
>>> M.__next__()
1
>>> N = M
>>> N.__next__()
0
自定义可迭代对象
构建一个自定义容器对象,
class Node:
def __init__(self,*value):
self._children = list(value)
def __iter__(self):
return iter(self._children)
N = Node(1,2,3,4,5)
for i in N:
print(i,end = ' ')
#1 2 3 4 5
# #只需要定义一个__iter__方法,将迭代操作代理到容器内部的对象上
去。
生成器
生成器本质就是迭代器,生成器的两种构建方式:1.生成器函数 2.生成器表达式。
- 生成器函数:编写常规的def语句,使用yield语句返回一个结果,在每个结果之间挂起和继续它们的状态
- 生成器表达式:返回一个按需产生结果的一个对象,而不是构建一个结果列表。
二者都不会一次性构建一个列表,节省了内存空间,将计算事件分散到各个结果请求。
生成器函数
def gensquares(n):
for i in range(n):
yield i ** 2
def gensquares(n):
for i in range(n):
yield i ** 2
g = gensquares(3)
print(g)
#<generator object gensquares at 0x03982B30>
print(g.__next__())
print(g.__next__())
#
0
1
send和next
调用g.send(value)发送给生成器g,并且生成器中的yield表达式返回了为了发生而传入的值。
def gen():
for i in range(5):
x = yield i
print(x)
G = gen()
g = G.__next__()
print(g)
G.send(9) # 必须先调用__next__()
g = G.__next__()
print(g)
#结果:
0
9
None #x接收send发送的值,没有发送默认为None
2
生成器表达式
G = (x*2 +1 for x in range(4))
G.__next__()
def add(a, b):
return a + b
def test():
for r_i in range(4):
yield r_i
g = test()
for n in [2, 10]:
g = (add(n, i) for i in g)
print(list(g))
#[20,21,22,23]
不要局部地关注for in g, (add(n, i) for i in g)这个表达式整体是一个生成器
并没有调用__next__方法。for每循环一次,n被重新赋值,并对g(表达式左边)重新赋值,生成器表达式随之发生改变。
第一次 n = 2,g = (add(n, i) for i in text())
第二次 n = 3,g = (add(n, i) for i in ((add(n, i) for i in text())))
..........
循环结束时 n = 10 g = (add(n, i) for i in ((add(n, i) for i in text())))