重修课程day12(函数之迭代器和生成器)
Posted 方杰0410
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重修课程day12(函数之迭代器和生成器)相关的知识,希望对你有一定的参考价值。
面向过程编程
面向过程编程是一种以过程为中心的编程思想,分析出解决问题的步骤,然后用函数把这些步骤一步一步实现。面向过程编程,数据和对数据的操作是分离的。
写程序时:要先想功能,分步实现
os模块中walk输出目录中文件路径,os.walk() 方法用于通过在目录树中游走输出在目录中的文件名,向上或者向下。
Send可以传多个值,但是必须是元组类型。面向过程的编程思想像流水线,代码简洁,体系结构。
#应用:grep -rl \'root\' /etc import os def init(func): def wrapper(*args,**kwargs): g=func(*args,**kwargs) next(g) return g return wrapper #阶段一:递归地找文件的绝对路径,把路径发给阶段二 @init def search(target): \'search file abspath\' while True: start_path=yield g = os.walk(start_path) for par_dir, _, files in g: # print(par_dir,files) for file in files: file_path = r\'%s\\%s\' % (par_dir, file) target.send(file_path) #阶段二:收到文件路径,打开文件获取获取对象,把文件对象发给阶段三 @init def opener(target): \'get file obj: f=open(filepath)\' while True: file_path=yield with open(file_path,encoding=\'utf-8\') as f: target.send((file_path,f)) #阶段三:收到文件对象,for循环读取文件的每一行内容,把每一行内容发给阶段四 @init def cat(target): \'read file\' while True: filepath,f=yield for line in f: res=target.send((filepath,line)) if res: break #阶段四:收到一行内容,判断root是否在这一行中,如果在,则把文件名发给阶段五 @init def grep(target,pattern): \'grep function\' tag=False while True: filepath,line=yield tag #target.send((filepath,line)) tag=False if pattern in line: target.send(filepath) tag=True #阶段五:收到文件名,打印结果 @init def printer(): \'print function\' while True: filename=yield print(filename) start_path1=r\'C:\\Users\\Administrator\\PycharmProjects\\python5期\\a\' start_path2=r\'C:\\Users\\Administrator\\PycharmProjects\\python5期\\a\\b\' g=search(opener(cat(grep(printer(),\'root\')))) print(g) # g.send(start_path1) g.send(start_path2) #应用:grep -rl \'root\' /etc
一 迭代器
迭代的意思:类似于循环每一次重复的过程就被称为迭代的过程,提供迭代方法的容器称为迭代器。
1.迭代器协议是指:迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,知道所有的元素被访问完结束。迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退。
2.可迭代对象:实现了迭代器协议的对象(如何实现:对象内部定义一个__iter__()方法),对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代
3.协议是一种约定,可迭代对象实现了迭代器协议,python的内部工具(如for循环,sum,min,max函数等)使用迭代器协议访问对象。
集合的目的:去重,关系运算。
# a={1,2,3,4,5,6,7} # b={41,52,5,26,7,4,2,9,} # print(a-b)
isinstance:判断数据的类型,还可以判断是否可迭代。
iterable:形容词 可迭代的:from collections import Iterable:用来检测一个对象是否可以迭代。
# from collections import Iterable # print(isinstance(\'fadda\',Iterable))
dir:打印一种数据类型的方法
print(dir(\'asdasf\'))
什么叫做可迭代对象:操作的对象下面有__iter__()方法的就是可迭代对象。
什么叫做迭代器:操作的对象下面不光有__iter__()方法的,还有__next__()方法的就是迭代器,迭代器是不用关心值得索引状态的
iterator:迭代器:实现了能从其中一个一个的 取值出来。
lst_iterator=[1,2,3,4,5].__iter__() print(lst_iterator.__next__())
一切可以用for循环的基本数据类型都是可迭代对象,而不是迭代器。for循环的可以是一个可迭代对象,也可以是一个迭代器。而for循环自动为可迭代对象调用__iter__()方法。
for i in [1,2,3,4,5,6]: print(i)
文件本质就是一个迭代器。range()就是一个可迭代对象,可迭代对象有:字符串,列表,元组等等。
__iter__():将一个可迭代对象转化成一个迭代器
__next__():读取迭代器的内容,一次只能读取一行或者一个内容
# with open(\'a.txt\',encoding=\'utf-8\')as f: # print(f.__next__()) # print(f.__next__()) # print(f.__next__()) # print(f.__next__()) # print(f.__next__()) # # b=[41,52,5,26,7,4,2,9,] # bb=b.__iter__() # print(bb.__next__()) # print(bb.__next__()) # print(bb.__next__()) # print(bb.__next__()) # print(bb.__next__())
迭代器取到没有值的时候就会报错。报的是StopIteration。
迭代的概念:重复的过程称为迭代,每次重复即一次迭代,并且每次迭代的结果是下一次迭代的初始值
迭代器的好处:1 能够对python中的基本数据类型进行统一的遍历,不需要关系每一个值是什么。
2 惰性预算:可以节省内存。
# for i in range(1,1000): # print(i) # if i == 100: # break
迭代器的坏处:
无法获取长度
一次性的,只能往后走,不能往前退
迭代器的创建:1 天生就是一个迭代器,比如说:文件句柄
2 后天转换成迭代器:迭代器=可迭代对象.__iter__()
二 生成器
什么是生成器(Gerator):生成器本质就是一个迭代器,生成器就是自己写出来的迭代器。
什么是生成器函数:函数里有yield的关键字就是一个生成器函数。
# def iter_1(): # print(111) # yield 222 # print(333) # yield 444 # # iter_2=iter_1() # print(iter_2.__next__()) # print(iter_2.__next__())
yield:意思和return差不多,但是yiled可以定位当前取值的位置,就是在next取值过后,就定位到取到的那个值的位置,等再次使用next取值的时候,就从第一次取值过后定位的那个位置开始取值,一个next对应一个yield。
from:yield下的一个方法,可以简化生成器函数。用了from,就可以不用for循环。
# def foo(): # for i in [1,2,3,4,5,6,7]: # yield i # for i in foo(): # print(i) # def foo(): # yield from [1,2,3,4,5,6,7] # for i in foo(): # print(i)
生成器函数在调用的时候返回来的就是一个生成器,不会执行生成器函数里面的内容。
# def iter_1(): # print(111) # yield 222 # print(333) # yield 444 # # iter_2=iter_1() # print(iter_2)
而生成器和迭代器运行的顺序是只能往前取值,而不能够回头。
生成器的用法:1 有几个next,就取几个yield的返回值,不能超过yiled的范围。
2 直接for循环取值:for 变量名 in 生成器名。
3 其他数据类型进行强转,list(数据类型对象)返回一个列表,里面装着生成器的所有内容。
for i in range(1,10): print(i) print(list(range(10,20)))
注意:1 生成器函数取值必须先转换成生成器,在进行next取值。
2 生成器的内容只能取一次,不能重复,只能向前取值;不能后退,直到取完为止。
惰性运算:生成器里面的内容不获取,不生成。
为函数封装好了__iter__和__next__方法,把函数的执行结果做成了迭代器
遵循迭代器的取值方式obj.__next__(),触发的函数的执行,函数暂停与再继续的状态都是由yield保存的
协同程序,就是可以运行的独立函数调用,保留函数的局部变量等数据,让函数可以暂停或者挂起。并且在需要的时候会从上次执行的后面第一个地方继续执行。
yield表达式
yield关键字用来定义生成器(Generator),其具体功能是可以当return使用,从函数里返回一个值,不同之处是用yield返回之后,可以让函数从上回yield返回的
地点继续执行。也就是说,yield返回函数,交给调用者一个返回值,然后再“瞬移”回去,让函数继续运行, 直到吓一跳yield语句再返回一个新的值,能多次重复使用。
使用yield返回后,调用者实际得到的是一个迭代器对象,迭代器的值就是返回值,而调用该迭代器的next()方法会导致该函数恢复yield语句的执行环境继续往下跑,
直到遇到下一个yield为止,如果遇不到yield,就会抛出异常表示迭代结束。
1. 包含yield的函数
假如你看到某个函数包含了yield,这意味着这个函数已经是一个Generator,它的执行会和其他普通的函数有很多不同。
调用函数之后,print 语句并没有执行!这就是yield,那么,如何让print 语句执行呢?这就是后面要讨论的问题,通过后面的讨论和学习,就会明白yield的工作原理了。
2. yield是一个表达式
Python2.5以前,Python yield是一个语句,但现在2.5中,yield是一个表达式(Expression)
假如,m=yield 5。表达式(yield 5)的返回值将赋值给m,所以,认为 m = 5 是错误的。那么如何获取(yield 5)的返回值呢?需要用到后面要介绍的send(msg)方法。
3. 透过next()语句看原理
现在,我们来揭晓yield的工作原理。我们知道,函数被调用后并没有执行,因为它有yield表达式,因此,我们通过next()语句让它执行。next()语句将恢复Generator执行,
并直到下一个yield表达式处。
当我们再次调用print(next(*))时,会继续执行,直到找到下一个yield表达式。由于后面没有yield了,因此会拋出异常:
4. send(msg) 与 next(),
了解了next()如何让包含yield的函数执行后,我们再来看另外一个非常重要的函数send(msg)。其实next()和send()在一定意义上作用是相似的,区别是send()可以传递yield表达式的
值进去,而next(*)不能传递特定的值,只能传递None进去。因此,我们可以看做next(*) 和 *.send(None) 作用是一样的。
需要提醒的是,第一次调用时,请使用next()语句或是send(None),不能使用send发送一个非None的值,否则会出错的,因为没有Python yield语句来接收这个值。
5. send(msg) 与 next()的返回值
send(msg) 和 next()是有返回值的,它们的返回值很特殊,返回的是下一个yield表达式的参数。
其实是每次都调用了alist.Next(),而每次alist.Next()的返回值正是yield的参数,即我们开始认为被压进去的东东。
6 可以为wield表达式创建一个装饰器,就是在多个表达式开始执行前不用每个都输入next(*) 和 *.send(None),为next(*) 和 *.send(None)创建一个装饰器,在每个wield表达式
函数名称前加上@装饰器的名称。装饰器为此提供了方便,可以多个一起使用。
三 文件补充小知识
文件下seek()传的值:0:光标的相对位置;1:当前光标的位置;2:将光标一道最后一个一个位置。
# def aa(bb,dd): # with open(bb,\'w\',encoding=\'utf-8\')as f : # f.write(dd) # aa(\'a.txt\',\'afdfd\\nfadsa\') # def tail(cc): # f=open(cc,encoding=\'utf-8\') # f.seek(0,2) # while True: # line=f.readline() # if not line: # continue # yield line # tail_g=tail(\'a.txt\') # for line in tail_g: # print(line,end=\'\') #
以上是关于重修课程day12(函数之迭代器和生成器)的主要内容,如果未能解决你的问题,请参考以下文章