python之迭代器

可迭代对象就是序列观念的通用化,如果对象是实际保存的序列,或者可以在迭代工具环境(eg:for循环)中一次产生一个结果的对象,就可看成是可迭代的。可迭代对象包括实际序列和按照需求而计算的虚拟序列。

常见的迭代工具:for循环、列表解析、in成员关系测试以及map内置函数等。

1. 文件迭代器

  • 文件中的readline方法和__next__方法
#**************************readline方法*************************************
f=open('salary.txt')
f.readline()        #return:'lastName hoursWorked hourlyWage\n'
f.readline()        #return:'Bob 4 80\n'
f.readline()        #return:'Ann 8 160\n'
f.readline()        #return:''

#**************************__next__方法*************************************
f=open('salary.txt')
f.__next__()        #return:'lastName hoursWorked hourlyWage\n'
f.__next__()        #return:'Bob 4 80\n'
f.__next__()        #return:'Ann 8 160\n'
f.__next__()        #捕捉StopIteration异常

区别:readline方法到达文件末尾时,返回空字符串。而__next__方法到达文件末尾时,会引发内置的StopIteration异常。

  • 逐行读取文本文件的最佳方式是for循环+__next__方法(该方法在for循环中自动调用__next__方法):与readlines方法相比,是最简单的写法,运行最快,内存使用也最少。readlines其实是一次把整个文件加载到内存,若文件过大,将导致计算机内存空间不够,甚至不能工作。
#**************************__next__方法*************************************
for line in open('salary.txt'):
    print(line,end='')
#**************************readline方法*************************************
for line in open('salary.txt').readlines():
    print(line,end='')

"""
result:
lastName hoursWorked hourlyWage
Bob 4 80
Ann 8 160
"""    

注意:print使用end=''来抑制每行最后添加一个\n,因为行字符串已经有一个啦,若没有end='',输出将两行隔开。

当然,以上也可以使用while循环来实现,但比for循环运行慢。

2.手动迭代:iter和next

对于一个可迭代对象X,调用next(X)等同于X.__next__()

#手动迭代
L=[1,2,3]
I=iter(L)
I is L            #return :False
I.__next__()      #return :1
I.__next__()      #return :2
next(I)           #return :3
next(I)           #捕捉StopIteration异常
#自动迭代
L=[1,2,3]
for i in L:
    print(i)

注意:列表以及很多其他的内置对象,不是自身的迭代器,因为它们支持多次打开迭代器。对于这样的对象,我们必须调用iter来启动迭代。

再举一个例子,字典的迭代

#字典的手动迭代,返回的是键值
D={'a':1,'b':2,'c':3}
I=iter(D)
next(I)     #return :'a'
next(I)     #return :'b'
next(I)     #return :'c'
#字典的自动迭代
for key in D:
    print(key,D[key])

#字典视图迭代器,当要显示时,需使用list()函数来显示
#字典中keys方法返回可迭代的视图对象
for key in D.keys():
    print(key)
#字典中values方法返回可迭代的视图对象  
for val in D.values():
    print(val)
#字典中items方法返回可迭代的视图对象   
for k,v in D.items():
    print(k,v) 

3. 其他迭代环境

除了for循环外,列表解析、in成员关系测试、map内置函数、sorted和zip等函数都使用了迭代协议,当应用于一个文件时,这些迭代器都会自动按行扫描。

#map函数
list(map(str.upper,open('salary.txt')))
#result:['LASTNAME HOURSWORKED HOURLYWAGE\n', 'BOB 4 80\n', 'ANN 8 160']
#in函数
'Bob 4 80\n' in open('salary.txt')    #return:True
'Ann 4 80\n' in open('salary.txt')    #return:False
#sorted函数
sorted(open('salary.txt'))
#result:['Ann 8 160', 'Bob 4 80\n', 'lastName hoursWorked hourlyWage\n']
#zip函数
list(zip(open('salary.txt'),open('salary.txt')))
#result:[('lastName hoursWorked hourlyWage\n', 'lastName hoursWorked hourlyWage\n'),('Bob 4 80\n', 'Bob 4 80\n'),('Ann 8 160', 'Ann 8 160')]
#enumerate函数
list(enumerate(open('salary.txt')))
#result:[(0, 'lastName hoursWorked hourlyWage\n'), (1, 'Bob 4 80\n'), (2, 'Ann 8 160')]
#filter函数,返回可迭代对象中为True的项,True项包括非空项
list(filter(bool,['spam','','ni']))     
#result:['spam','ni']

4. 重访迭代器:生成器

4.1 介绍

生成器有两种:生成器函数和生成器表达式,它们在需要的时候才产生结果,而非立即产生结果,延迟了结果创建,节省了内存空间,并允许计算时间分散到各个结果请求。

  • 生成器函数:常规的def语句,但使用yield语句一次返回一个结果,在每个结果之间挂起和继续它们的状态。
  • 生成器表达式:类似列表解析,但是,它们返回按需产生结果的一个对象,而不是构建一个结果列表。

状态挂起:和返回一个值并退出的常规函数不同,生成器函数自动在生成值的时刻挂起并继续函数的执行。

迭代协议整合:编写包含yield语句的def语句,将自动支持迭代协议,并且由此可能在任何迭代环境中以随着时间并根据需要产生结果。

4.2 生成器函数的应用

#定义生成器函数,用来产生一系列的数字的平方
def gensquares(N):
    for i in range(N):
        yield i**2
        
#使用上面创建的生成器        
for i in gensquares(5):
    print(i,end=' ')

上述例子,也可以通过for循环、map或者列表解析的技术来实现,但是,相比较下,生成器在内存使用和性能方面都表现的更好,且能避免临时再做所有的工作。有了生成器,函数变量就能够自动的保存和恢复了。

4.3 生成器表达式:迭代器+列表解析

从语法上来讲,生成器表达式就像一般的列表解析一样,但是它们是括在圆括号中而非方括号中。

#列表解析
[x**2 for x in range(4)]   #result:[0, 1, 4, 9]
#生成器表达式
(x**2 for x in range(4))   #result: <generator object <genexpr> at 0x0000000009BD0CA8>
#调用list函数显示生成器结果
list(x**2 for x in range(4))   #result:[0, 1, 4, 9]
#for循环自动触发生成器
for i in (x**2 for x in range(4)):
    print(i)            

#如果生成器表达式是在其他的括号之内,例如函数调用,此时,生成器自身的括号则可以省略
sorted(x**2 for x in range(4))                    #result:[0, 1, 4, 9]
#但,如果是这样,则还是需要额外的括号的
sorted((x**2 for x in range(4)),reverse=True)     #result:[9,4,1,0]

4.4 生成器函数 VS 生成器表达式

生成器函数和生成器表达式自身都是迭代器,并只支持一次活跃迭代,且都支持自动迭代和手动迭代。有趣的是,往往同样的迭代可以用一个生成器函数或生成器表达式编写。等价的生成器函数需要略微多一些的代码,但作为一个多语句的函数,如果需要的话,它将能编写更多逻辑并使用更多的状态信息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值