python 迭代详解_python——迭代和解析

一般来说,生成器函数和常规函数一样,并且实际上也是用常规的def语句编写的。然而,当创建时,他自动实现迭代协议,以便可以出现在迭代背景中。

0.迭代协议

有__next__方法的对象会前进到下一个结果,当到达结尾时则会引发StopIteration异常。在python中,任何这类对象都认为是可迭代的。任何这类对象也能以for循环或其他迭代工具遍历,因为所有迭代工具内部工作起来都在每次迭代中调用__next__,并且捕捉StopIteration异常来确定何时离开。

#读取文本文件的最佳方式就是根本不要去读取;代替的办法是让for循环在每轮自动调用next从而前进到下一行#这是读取文本文件的最佳方式,因为写法最简单,运行最快,并且从内存使用情况来说也是最好的。#这个和for line in f.readlines是一个效果

l =list()

with open('../data/123.txt') as f:#a = f.readline()

for line inf:print(line, end='') #end=''是为了抑制一个\n 因为已经有一个\n了

l.append(line)print(l)

1.手动迭代:iter和next

python3提供了一个内置函数next,它会自动调用一个对象的__next__方法。给定一个可迭代对象X,调用next(X)等同于X.__next__()。

手动迭代的方法就是先创建一个迭代器(iter),然后通过迭代器的next方法进行迭代。具体做法如下:

D = {'a':'A','b':'B','c':'C'}

I=iter(D)print(next(I)) #a

print(next(I)) #b

但是对于文件来说,是不需要初始化迭代器的(上面代码第二行),因为文件对象就是自己的迭代器。也就是说,文件有自己的__next__方法,因此不需要像这样返回一个不同的对象。列表以及很多其他的内置对象,不是自身的迭代器,因为它们支持多次打开迭代器。对这样的对象,我们必须调用iter来启动迭代,他们(dict, list)没有自己的__next__方法:

D = {'a':'A','b':'B','c':'C'}

I=iter(D)if iter(D) isD:print('true')elif iter(D) isI:print('I is iter') # 我本来以为会打印这一句,结果不是的,不知道为什么

else:print('dict dont have __next__ func') #print this one

f = open('../data/123.txt')print(f.__next__())if iter(f) isf:print('TRUE') #print this one

2.列表解析

例如以下代码就是一个常见的列表解析:

L = range(10)

L= [x + 10 for x in L] #[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

在文件中readlines方法可以一次性地吧文件载入到行字符串的一个列表中,这个有效但是结尾会含有一个换行符。去掉换行符,并保存到一个列表的写法如下:

lines = [line.rsplit() for line in open('123.txt')] #rsplit反向去掉空格(换行符)

增加测试和嵌套循环的列表解析:

[x for x in range(5) if x %2 ==0] #[0, 2, 4]

list(filter((lambda x: x % 2 ==0), range(5))) #[0, 2, 4]

再复杂点的:

list(map((lambda x: x**2), filter((lambda x: x %2 ==0), range(10))))#[0, 4, 16, 36, 64]

矩阵中使用:

M = [[1,2,3],

[4,5,6],

[7,8,9]]

[row[1] for row in M] #[2,5,8]

3.理解解析列表

优点:map调用比等效的for循环要快两倍,而列表解析往往比map调用要稍快一些。速度上的差距是来自于底层实现上,map和解析列表是在解释器中以C语言的速度来运行的,比python的for循环化代码在PVM中步进运行要快的多。

缺点:解析列表和map没有for循环逻辑清晰。

4.生成器

生成器函数:编写为常规的def语句,但是使用yield语句一次返回一个结果,在每个结果之间挂起和继续它们的状态。

生成器表达式类似于列表解析,但是,它们返回按需产生结果的一个对象,而不是构建一个结果列表,从语法上讲,生成器表达式就像一般的列表解析一样,但是它们是括在圆括号中而不是方括号中的。

由于二者都不会一次性构建一个列表,它们节省了内存空间,并且允许计算时间分散到各个结果请求。

4.1生成器函数: yield VS return

状态挂起

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

生成器函数和常规函数之间的主要的代码不同之处在于,生成器yields一个值,而不是return一个值。yield语句挂起该函数并向调用者发送回一个值(return 则直接返回结果并结束了这个func),但是,保留足够的状态以使得函数能够从它离开的地方继续。当继续时,函数在上一个yield返回后立即继续执行。

迭代协议整合

迭代协议:可迭代的对象定义了一个__next__方法,它要么返回迭代中的下一项,或者引发一个特殊的stopIteration异常来终止迭代。一个对象的迭代器用iter内置函数接受。

实现方法:如果函数中包含了yield 语句(注意是语句不是函数),该语句则会编制为生成器。即自动实现迭代器协议。当调用生成器的时候,它返回一个迭代器对象,该对象支持用一个名为__next__的自动创建的方法来继续执行的接口。生成器喊也可能有一条return语句,总是在def语句块的末尾,直接终止值的生成。从技术上讲,可以在任何常规函数退出执行以后,引发一个stopIteration异常来实现。

生成器函数应用

defa(n):for i inrange(n):yield i ** 2

for i in a(5):print(i, end=':') #0:1:4:9:16:

x= a(5)print(type(x)) #generator

print(x.__next__()) #0

print(next(x)) #1

print(next(x)) #4

扩展生成器函数协议:send和next

再更新

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值