Python基础--迭代器与生成器

可迭代对象

首先我们明确一个概念我们了解的数据类型哪些是可迭代对象,什么又叫可迭代对象呢?
可迭代对象包括以下几种数据类型
  • 字符串
  • 列表
  • 元组
  • 字典
  • 集合
字符串、列表、元组、字典、集合都可以被for循环说明他们都是可迭代的
from collections import Iterable
                             
l = [1,2,3,4]                
t = (1,2,3,4)                
d = {1:2,3:4}                
s = {1,2,3,4}                
                             
print(isinstance(l,Iterable))
print(isinstance(t,Iterable))
print(isinstance(d,Iterable))
print(isinstance(s,Iterable))
我们现在是从结果分析原因,能被for循环的就是“可迭代的”,但是如果正着想,for怎么知道谁是可迭代的呢?

假如我们自己写了一个数据类型,希望这个数据类型里的东西也可以使用for被一个一个的取出来,那我们就必须满足for的要求。这个要求就叫做“可迭代协议”。
可迭代协议的定义非常简单,就是内部实现了__iter__方法

总结一下我们现在所知道的:可以被for循环的都是可迭代的,要想可迭代,内部必须有一个__iter__方法;
#我们通过代码验证一下
print(dir([1,2]))
print(dir((2,3)))
print(dir({1:2}))
print(dir({1,2}))
#我们通过结果发现这些数据类型内部都含有__iter__方法;

迭代器

迭代器又是什么鬼,他和可迭代对象有什么区别吗?我们来一一分析;
可迭代对象:内部有__iter__方法
迭代器:迭代器遵循迭代器协议:必须拥有__iter__方法和__next__方法;
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)

迭代器的特性

  • 非常节省内存
  • 满足惰性机制
  • 一条路走到黑不能回头
for循环能遍历一个可迭代对象他的内部到底进行了什么?
1.将可迭代对象转化成迭代器。(可迭代对象.__iter__())
2.内部使用__next__方法,一个一个取值。
加了异常处理功能,取值到底后自动停止
#利用while循环模拟for循环机制
#1.将可迭代对象转换成迭代器
#2.利用next方法进行取值
#3.利用异常处理终止循环
l1 = [1,2,3,4,"alex"]
inter1 = l1.__iter__()
while True:
    try:
        print(inter1.__next__())
    except StopIteration:
        break
序列类型字符串 列表 元组都有下标 可以用下标的方式访问,但是非序列类型像字典集合 文件对象就没有下标;for循环就是基于迭代器协议提供了统一的可以遍历所有对象的方法,即在遍历之前,先调用对象的__iter__方法将其转换成一个迭代器,然后使用迭代器协议去实现循环访问,这样所有的对象就都可以通过for循环来遍历了,而且你看到的效果也确实如此,这就是无所不能的for循环,最重要的一点,转化成迭代器,在循环时,同一时刻在内存中只出现一条数据,极大限度的节省了内存;

生成器

自己用python代码写的迭代器,本质就是迭代器;
我们知道的迭代器有两种:一种是调用方法直接返回的,一种是可迭代对象通过执行iter方法得到的,迭代器有的好处是可以节省内存;

如果在某些情况下,我们也需要节省内存,就只能自己写。我们自己写的这个能实现迭代器功能的东西就叫生成器;

Python中提供的生成器:
1.生成器函数:使用yield语句而不是return语句返回结果;yield语句一次返回一个结果;在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行;

2.生成器表达式:类似于列表推导,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表;
生成器函数
一个包含yield关键字的函数就是一个生成器函数;
yield可以为我们从函数中返回值,但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象,每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值直到函数执行结束;
生成器有什么好处呢?就是不会一下子在内存中生成太多数据;
def func():
    print(1111)
    print(2222)
    yield 3 #返回值
func()  #生成器对象
#一个next对应一个yield
def cloth1():
for i in range(1,201):
    yield "T恤%s号" %(i)
g = cloth1()

for i in range(5):
    print(g.__next__())

for i in range(195):
    print(g.__next__())

列表推导式

凡是列表推到是能构建的数据,Python代码都能构建,列表推导式不能构建的数据,Python代码仍然可以构建
循环模式
语法格式:列表 = [加工后的变量 for 变量 in 可迭代对象]
l1 = [i for in rang(1,101)]
print(l1)

l1 = ["Python%s期"%i for i in range(1,24)]
print(l1)
筛选模式
l1 = [i for i in range(31) if i % 2 == 0]
print(l1)

#10以内所有值的平方
l1 = [i ** 2 for i in range(10)]
print(l1)

#30以内能被3整除的平方
l2 = [i ** 2 for i in range(31) if i % 3 == 0]
print(l2)

生成器表达式

#使用小括号包含,其他规则与列表推导式一致
g1 = (i for i in range(10000000))
print(g1.__next__())
列表推导式 生成器表达式
优点:构建简答 一行完成

缺点:不方便调试
     不能构建复杂的数据结构

猜你喜欢

转载自www.cnblogs.com/olingrobin/p/10174452.html