python基础梳理(十九)迭代器、生成器以及迭代工具函数(zip、enumerate)

一、迭代器 Iterator 和 生成器 Generator
1.什么是迭代器:
迭代器是访问可迭代对象的一种方式,用迭代器可以访问可迭代
迭代器是指iter(可迭代对象)返回的对象
迭代器可以用next(it)函数获取可迭代对象中的数据

2.迭代器相关的函数
1)iter(iterable)
从可迭代对象中返回一个迭代器,iterable必须是能提供一个迭代器的对象
2)next(iterator)
从迭代器iterator中获取下一个元素。如果无法获取下一个元素,则触发StopIterator异常

3.迭代器说明:
迭代器只能往前取值,不会后退
用iter函数可以返回一个可迭代对象的迭代器

示例1:以前我们访问可迭代对象使用for循环,这里示例迭代器访问

for循环打印可迭代对象原理,实际上while循环 + iter 迭代器方式等价
见示例3

for   x   in   L:      #实际也是用可迭代对象的迭代器访问的
    print(x)
L = [1,2,3,4,5,6]
it = iter(L)
print(it)
print(next(it))
print(next(it))
print(next(it))
print(next(it))
print(next(it))
print(next(it))
print(next(it))

执行结果:
<list_iterator object at 0x0000018838463828>
1
2
3
4
5
6
StopIteration
#当可迭代对象中的元素被遍历完后,继续遍历会触发一个StopIteration的异常

示例2:用迭代器访问获取range对象的数据

it = iter(range(5,10))

print(it)
print(next(it))
print(next(it))
print(next(it))
print(next(it))
print(next(it))
print(next(it))
执行结果:
5
6
7
8
9
StopIteration

示例3.用while循环访问可迭代对象中的元素,并且进行异常捕获
for循环遍历可迭代对象其实就是对while循环 + iter +异常处理进行的封装

L = [1,2,3,4,5,6]
it = iter(L)
while True:
    try:
        x = next(it)
    except StopIteration:
        break
    print(x)
执行结果:
1
2
3
4
5
6
    

示例4:分别用for循环和while循环访问可迭代对象s

s = {"工商银行","建设银行","中国银行","农业银行"}

for x in s:
    print(x,end = ' ')

print()
it = iter(s)
while True:
    try:
        x = next(it)
        print(x, end=' ')
    except StopIteration:
        break
执行结果:
工商银行 农业银行 建设银行 中国银行 
工商银行 农业银行 建设银行 中国银行 

二、生成器 genertor (python 2.5及以后的版本)
1.什么是生成器
生成器是能够动态提供数据的对象,生成器对象也是可迭代对象
2.生成器的种类:
生成器函数
生成器表达式
3.生成器函数定义:
含有yield语句的函数是 生成器函数,此函数被调用将返回一个生成器对象
yield翻译为产生或生成
4.yield语句:
语法:
yield 表达式
说明:
yield 用于def 函数中,目的是将此函数作为生成器函数使用
yield用来生成数据,共next(it)函数使用

动态提供数据和静态提供数据:

静态:已经存在,直接拿来用

L = [1,2,3,4]
for x in L:
    print(x)
 #实际上x取的数据已经存在在内存中,我们直接拿来用就OK,不是运行的时一个一个的生成

动态:运行的时候再去生成这些数据

for x in range(1000000000000000000):
    print(x)
#实际上,range不会一次性就将这所有的数据都生成出来,而是会运行时再去一个一个的生成,访问过的被释放,“现用现生成”,会使计算机效率更高

示例1:定义一个yield函数

def myyield():
    yield 2
    yield 2+1
    yield 5
    yield 7
    print("生成器函数调用结束")
myyield()
执行结果:无
#并没有打印函数中的要打印的语句,这是为什么?

示例2:解释示例1的现象
myyied函数实际上返回来的时生成器对象,即使没有return语句,该对象为可迭代对象

#即使调用了这个函数,实际上并没有执行,因为没有打印
gen = myyield()
print(gen)
执行结果:
<generator object myyield at 0x00000219F1727DB0>

既然这个生成器对象可以迭代,我们可以看一下有什么东西

for x in gen:
    print(x,end = " ")
 执行结果:
 2 3 5 7 生成器函数调用结束

那当然可以用它返回的迭代器访问它了,这里我们使用while循环来访问这个生成器对象

it = iter(gen)
while True:
    try:
        x = next(it)
        print(x,end = " ")
    except StopIteration:
        break
执行结果:
2 3 5 7 生成器函数调用结束

图解这个特殊函数的调用中的各种复杂关系:
在这里插入图片描述
上图补充一句:等到生成器对象去向函数要数据的时候,这个生成器函数才会被调用
也就是说:gen = myyield()并没有调用函数

为什么要有生成器:
一切为了效率!!!!!! 现用现生成!!!!!!
实际上有的我们可以不必为用户提前生成一大堆的数据:
优点
1.生成一大堆数据会占用大量的内存,就拿我们熟悉的列表来说,我们定义好了,系统就要为我们创建那么多的对象,相应的也会占用大量的内存,在数据量非常大的时候,静态的提供数据效率就显得很低了
2.能快速的响应客户,不用客户等待那么久,生成一个给用户送一个,我觉得用户可能更喜欢这样的响应方式,而不是等待很久所有数据生成后才得到回应。

缺点:
需要进行生成器函数、生成器对象、迭代器之间来回的传递数据,可能会浪费一些时间

总结:
对于海量数据问题时,函数生成器可以降低内存占用率,降低用户响应的等待时间

练习:
写一个生成器函数,my_integer(n)生成1到n之间的整数

def my_integer(n):
    i = 1
    while i< n:
        yield i
        i += 1

for x in my_integer(10):
    print(x,end =' ')
 执行结果:
 1 2 3 4 5 6 7 8 9 

range():就可以用yield来实现

练习:给定一个区间[start,end),使用函数生成器找出区间中的所有奇数,并打印出来

def myodd(start,end):
    i = start
    while i < end:
        if i % 2 != 0:
            yield i
            i += 1
        i += 1

it = iter(myodd(1,60))

while True:
    try:
        x = next(it)
        print(x,end = ' ')
    except StopIteration:
        break
执行结果:
1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 51 53 55 57 59 

三、生成器表达式
语法:
(表达式 for 变量 in 可迭代对象 [if 真值表达式])
注: []内的if部分可以省略

作用:
用推导的形式去生成一个新的生成器
示例:

gen = (x ** 2 for x in range(1,5))
it = iter(gen)
print(gen)
while True:
    try:
        x = next(it)
        print(x,end = ' ')
    except StopIteration:
        break
执行结果:
<generator object <genexpr> at 0x000001FA66237DB0>
1 4 9 16 

注:python中实际上有三种推导式:列表、集合、字典。
这里只是以推导式的形式来生成一个生成器

我们也可以从执行结果看出来,gen是个生成器对象

图解生成器表达式:
在这里插入图片描述

注:python中的生成器函数和表达式是处理海量数据的优势。不需要将数据完全存下来,取一个处理一个,效率比较高

四、迭代工具函数:
迭代工具函数的作用是生成一个个性化的可迭代对象

zip(iter1[,iter2,…]):
返回一zip对象,此对象用于生成一个元组,此元组的个数是由最小的迭代对象决定的
元组的内容始可迭代对象iter1和iter2中的元素的组合

enumerate(iterable[,start]):
生成带索引的枚举对象,返回的迭代器类型为索引 - 值 对儿(index - value)对
默认索引从0开始,也可以用start指定

注:[]内的内容可以省略

示例:zip用法

numbers = [10086,10000,10010,95588]         #四个元素
names = ['中国移动','中国电信','中国联通']#三个元素

for t in zip(numbers,names):
    print(t)
#每次分别从俩个可迭代对象中去一个元素,打包成一个元组
#如果其中的一个短的结束,打包的过程也结束,短板效应,以最短的为标准

#还可以将生成这些元组打包放在一个字典
d = dict(zip(numbers , names))
print(d)

执行结果:
(10086, '中国移动')
(10000, '中国电信')
(10010, '中国联通')
{10000: '中国电信', 10010: '中国联通', 10086: '中国移动'}

练习:自己动手写一个zip函数

def myzip(iter1,iter2):
    it1 = iter(iter1)
    it2 = iter(iter2)
    while True:
        try:
            yield (next(it1),next(it2))
        except StopIteration:
            break

numbers = [10086,10000,10010,95588]         #四个元素
names = ['中国移动','中国电信','中国联通']#三个元素
for t in myzip(numbers,names):
      print(t)
执行结果:
(10086, '中国移动')
(10000, '中国电信')
(10010, '中国联通')

示例:enumerate的用法,可以给一些数据加上序列,相当于给已经有的可迭代对象加上数据,进行包装。

names = ['中国移动','中国电信','中国联通']
for n in enumerate(names):
    print(n)

#自动会给数据加上0,1,2...索引
执行结果:
(0, '中国移动')
(1, '中国电信')
(2, '中国联通')

示例:第二个参数的作用

names = ['中国移动','中国电信','中国联通']
for n in enumerate(names,100):
    print(n)
 执行结果:
(100, '中国移动')
(101, '中国电信')
(102, '中国联通')

示例: enumerate的扩展写法

names = ['中国移动','中国电信','中国联通']
for k,n in enumerate(names,100):
    print(n,"的序号是",k)
执行结果:
中国移动 的序号是 100
中国电信 的序号是 101
中国联通 的序号是 102

示例:

it = iter(enumerate(names,1))

while True:
    try:
        k,n = next(it)
        print("序号:",k,'------>',n)
    except StopIteration:
        break
执行结果:
序号: 1 ------> 中国移动
序号: 2 ------> 中国电信
序号: 3 ------> 中国联通

练习:输入一些字符串,输入空格时结束输入,打印带有行号的字符串

L = []
def fun():
    while True:
        s = input("输入字符串:  ")
        if s == '':
            break
        else:
            L.append(s)
    for x,n in enumerate(L,1):
        print('序号:',n,"---------->",x)

fun()
执行结果:
输入字符串:  hello
输入字符串:  python
输入字符串:  小鸡鸡
输入字符串:  
序号: hello ----------> 1
序号: python ----------> 2
序号: 小鸡鸡 ----------> 3
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值