可迭代对象、迭代器和生成器

迭代(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())))
posted @ 2019-09-14 20:40  Sroxi  阅读(300)  评论(0编辑  收藏  举报