迭代器和生成器

迭代器

容器类型:list /  tuple / dict /set

容器类型取值方法

例:列表

#列表
#第一种方法:利用索引
l = [1,2,3,4]
print(l[0]) # 利用索引
print(l[:2])# 所有切片都相当于把一段内容取出来放在一个新列表中
print(l[:]) # 生成了一个新的列表,默认浅拷贝

# 所有的切片,都拷贝第一层, 对于没有嵌套的列表来说,切片就相当于深拷贝

#第二种:for循环
l = [1,2,3,4]
for i in l:
    print(i)

当需要对某一个列表中的每一个元素都需要的时候才用for循环
View Code

例:字典

dic = {'name':'wanglan','age':18}
#第一种方法:key
print(dic['name'])
print(dic['age'])
# #第二种方法:for循环
for k,v in dic.items():
    print(k,v)

for k in dic:             
    if  k == "name":
        print(dic[k])
View Code

整型

for i in 10:
    print(i)

结果:
    for i in 10:
TypeError: 'int' object is not iterable

报错:int类型不是一个iterable ,iterable表示可迭代的,说明整型不能迭代,可用使用dir()来查看数据类型是否可以迭代

print(dir([])) #判断列表
print(dir(())) #判断元组
print(dir(123)) #判断整型  :整型的内部不含有__iter__

如果输出内容函数__iter__方法,说明该数据类型是可迭代的
View Code

可迭代协议 : 只要是含有'__iter__' 方法的数据类型都是可迭代的

检查某个变量或值是不是可迭代的

#第一种检测方法
print('__iter__' in dir([]))
print('__iter__' in dir(123))
#结果:
True
False

#第二种检测方法
from collections import Iterable
print(isinstance([],Iterable))   # 内置函数,判断一个具体的值是不是某个数据类型的
print(isinstance(123,Iterable))

#结果:
True
False
View Code

可以迭代的都是可以使用for循环的

l = [1,2,3,4]
res = l.__iter__()
print(res)

结果:
<list_iterator object at 0x00000000025D80F0>  # iterator : 迭代器

迭代器和可迭代的区别

l = [1,2,3,4]
res = l.__iter__()
print(dir(res))
print(dir(l))
print(set(dir(res)) - set(dir(l)))  #在 res 中,但是不在 l 中的所以方法
 
结果:
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__length_hint__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__']
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
{'__length_hint__', '__setstate__', '__next__'}  #区别在此
View Code

__length_hint__ :查看迭代器中有多少个元素()

l = [1,2,3,4]
res = l.__iter__()
print(res.__length_hint__())  

结果:
4
View Code

__setstate__ :控制迭代器从哪儿开始迭代

l = [1,2,3,4]
res = l.__iter__()
res.__setstate__(2)
for i in res:
    print(i)
结果:
3
4
View Code

__next__:从迭代器中取下一个值

l = [1,2,3,4]
res = l.__iter__()
print(res.__next__())
print(res.__next__())
print(res.__next__())
print(res.__next__())

结果:
1
2
3
4
View Code

用迭代器的next方法来写一个不依赖for的遍历

l = [1,2,3,4]
l_iter = l.__iter__()
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)

结果:
   item = l_iter.__next__()
StopIteration
1
2
3
4
View Code

这段代码会报错,因为一直取next取到迭代器没有元素了,就会抛出StopIteration

使用异常处理机制来处理异常

l = [1,2,3,4]
l_iter = l.__iter__()
while True:
    try:
        item = l_iter.__next__()
        print(item)
    except StopIteration:
        break
View Code

迭代器协议 : 含有__next__和__iter__方法的变量/值都是迭代器

迭代器的特点:
  具有next和iter方法
  通过一个next多次执行就可以获得所有这个容器中的值
  迭代器中的值只能取一次
  不取的时候值不出现

for 循环取值:
  for循环内部的机制就是迭代器取值的机制
  在for循环执行的过程中 : 先把可迭代的变成一个迭代器,然后再从中一个一个的取值

本质上for循环替我们做的操作:
    1.生成迭代器
    2.循环每一次对这个迭代器执行next
    3.并且到迭代器的最后就停止

迭代器的作用就是节省内存,for循环就是利用了迭代器节省内存的特点来对python当中的变量来进行操作的

l = [1,2,3,4]
res1 = l.__iter__()
res2 = l.__iter__()
# res1和res2都是迭代器
# 是两个完全不同的迭代器
View Code
l = [1,2,3,4]
res1 = l.__iter__()
res2 = l.__iter__()

for i in res1:
    print(i)
print('**')

for i in res1:
    print(i)
print('--')

结果:
1
2
3
4
**
--
View Code

第二个for循环并没有打印,因为for循环内部的机制就是迭代器取值的机制,每个迭代器都只能取值一次

创建一个迭代器,循环这个迭代器,每次执行iter方法就创建一个迭代器,

l = [1,2,3,4]

for i in l.__iter__(): 
    print(i)
print('^^')
for i in l.__iter__():
    print(i)
结果:
1
2
3
4
^^
1
2
3
4
View Code

用while循环实现一个for循环的功能(循环list/dict)

l = [1,2,3,5,6,7,12,23,412]
l_iter = l.__iter__()
count = 0
while count < len(l):
    try:   # 要保护的代码
        print(l_iter.__next__())
    except StopIteration:  # 要保护的代码中一旦出现了StopIteration错误,程序不报错,直接执行break
        break
    count +=1
View Code

 生成器

迭代器有两种:

一种是调用方法直接返回的,一种是可迭代对象通过执行iter方法得到的,迭代器有的好处是可以节省内存。
如果在某些情况下,我们也需要节省内存,就只能自己写。我们自己写的这个能实现迭代器功能的东西就叫生成器

生成器函数:

常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行

本质:迭代器(所以自带了__iter__方法和__next__方法,不需要我们去实现)

特点:惰性运算,开发者自定义

定义:

 一个包含yield关键字的函数就是一个生成器函数。yield可以为我们从函数中返回值,但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。

定义一个生成器

def func():
    print('hello')
    yield 1
a = func()   #调用生成器函数,调用不会执行这个函数,而是返回一个生成器,a是一个生成器
g = a.__next__() #执行一次
print(g)
View Code
def func():
    print('hello')
    yield 1
    print('world')
    yield 2

g = func()
a = g.__next__()
print(a)
b = g.__next__()
print(b)
View Code

yield关键字的特点: 可以记录当前函数中执行的位置,下一次继续执行,需要next来触发这个函数继续向下执行

next和yield是一对搭档 : next开始函数的执行 yield停止函数的执行

生成器函数和其他函数[在本质上]我们得到的结果是相同的,只不过中间的过程不同

普通函数:必须得到所有结果之后才返回

生成器函数:可以一边计算结果一边返回

迭代器:

可迭代协议 : 某个变量中含有__iter__方法,这个变量可迭代
     迭代器协议 : 某个变量中含有__iter__和__next__方法,这个变量是迭代器
     迭代器和可迭代的关系:
         迭代器一定可迭代反之不成立
     迭代器的特点 :
         节省内存
         惰性运算
         只能取一次
         只能按照顺序取
     for循环和迭代器之间的关系
         如果是非迭代器,for循环会帮助我们把这个飞迭代器编程迭代器(通过iter方法)
         帮助我们执行next方法从迭代器中取值
         帮助我们处理异常停止迭代

生成器

生成器就是迭代器
     我们怎么获得生成器??
         生成器函数
         生成器表达式
     什么是生成器函数?
         含有yield方法
     生成器函数有什么特点?
         调用的时候不执行
         返回一个生成器/迭代器
         从生成器中取值的方式和迭代器一样

例:

def produce():
    """生产衣服"""
    for i in range(2000000):
        yield "生产了第%s件衣服"%i

product_g = produce()
print(product_g.__next__()) #要一件衣服
print(product_g.__next__()) #再要一件衣服
print(product_g.__next__()) #再要一件衣服
num = 0
for i in product_g:         #要一批衣服,比如5件
    print(i)
    num +=1
    if num == 5:
        break

结果:
生产了第0件衣服
生产了第1件衣服
生产了第2件衣服
生产了第3件衣服
生产了第4件衣服
生产了第5件衣服
生产了第6件衣服
生产了第7件衣服
View Code

监听文件的输入,对于文件中随时输入的内容进行自动化分析/自动化展示

def get_line():
    f = open('file',encoding='utf-8')
    while True:
        line = f.readline().strip()
        if line:
            yield line.strip()

line_g = get_line()

for line in line_g:
    print(line.split(','))
View Code

send

def func():
    print('草莓')
    yield 1
    print('香蕉味')
    yield 2
    print('榴莲')
    yield 3
g = func()
for i in g:
    print(i)
# 拆开for循环
# n = g.__next__()
# print(n)
# n = g.__next__()
# print(n)
# n = g.__next__()
# print(n)

# send
def func():
    print('草莓')
    wl = yield 1
    print(wl)
    yield 2
    print('榴莲')
    yield 3
g = func()
print(g.__next__()) #开头必须是__next__
print(g.send('香蕉')) #相当于g.__next__,只不过传入一个值进去
View Code

计算移动平均值

def fun():
    sum_n = 0
    count = 0
    while True:
        if count:
            num = yield sum_n/count #9 返回 4.0
        else:   # 2
            num = yield 0  #3 返回 0  # 6 num = 4 
        sum_n +=num  #7 sum_n = 4
        count +=1 #8 count = 1 
g = fun()
avg = g.__next__()    # 1
print(avg)  #4 0
avg = g.send(4) # 5 传入4 #10 返回4
print(avg) ##11 4.0
avg = g.send(5)
print(avg)
avg = g.send(6)
print(avg)
View Code

yield form

def func():
    l1 = [1,2,3]
    s2 = 'abc'
    yield from l1 #yield form 后面直接跟可迭代变量
    yield from s2
g = func()
for i in g:
    print(i)
View Code

其他

def func():
    lst = [1,2,3,4,5]
    return lst   #[1,2,3,4,5]
#lst = func()
for i in func():
    print(i)
def func():
    lst = [1,2,3,4,5]
    for num in lst:
        yield num
    #相当于
    # num = 1
    # yield num
    # num = 2
    # yield num
    # num = 3
    # yield num
    # num = 4
    # yield num
    # num = 5
    # yield num

#g = func() #生成器函数的返回值是一个生成器,生成器的本质是迭代器,g是一个生成器/迭代器
for i in func(): # g 和 func 是相同的
    print(i) #for 循环是通过迭代器实现的
#相当于
# print(g.__next__()) # 1 从生成器中,通过next取到的值才是yield的返回值
# print(g.__next__()) # 2
# print(g.__next__()) # 3
# print(g.__next__()) # 4
# print(g.__next__()) # 5

在python2.x中: range() 列表   xrange():生成器

在python3.x中:range() 可迭代的,既不是生成器也不是迭代器

原文地址:https://www.cnblogs.com/wanglan/p/9910209.html