1.处理文件,用户制定要查找的文件和内容,将文件中要查找内容的每一行都输出到屏幕
def func(filename,content): with open(filename,mode='r',encoding='utf-8') as file: while True: line=file.readline() if content in line: print(line.strip()) func('info','xuanxuan')
info 文件内容:
运行结果:
当然如果要是使用生成器函数来做的话可以这样写:
def generator(filename,content): with open(filename,mode='r',encoding='utf-8') as file: while True: line=file.readline() if content in line: yield line.strip() g=generator('info','xuanxuan') for i in g: print('符合用户指定内容的行:',i)
运行结果:
版本三(Eva-J):
def generator(filename,content): with open(filename,mode='r',encoding='utf-8') as file: #file 其实是一个文件句柄,就是拿着它可以操作跟文件相关的东西,相当于一个操作杆就是句柄 for line in file: if content in line: yield line.strip() g=generator('info','xuanxuan') for i in g: print(i)
运行结果:
2.写生成器,从文件中读取内容,每一次读取到的内容之前加上‘****’之后在返回给用户:
def generator(): with open('info',mode='r',encoding='utf-8') as file: while True: line=file.readline() #一行一行读取文件内容 if line.strip(): yield '*****'+line.strip() g=generator() for i in g: print(i)
运行结果:
版本二(Eva-J):
def generator(filename): with open(filename,mode='r',encoding='utf-8') as file: for line in file: yield '****'+line.strip() g=generator('info') for i in g: print(i)
运行结果:
面试题1
首先补充一个小的知识点:
我们可以使用生成器表达式产生一个生成器:
g=(i for i in range(10))
其实这个生成器表达式的效果和生成器函数效果是一样的:
def generator(): for i in g: yield i g=generator()
都不会被执行!!!,只有当使用for 循环或者使用g.__next__()时才会执行里面的代码(这里只是想说生成器表达式写在那就只是告诉我们哦我这里产生了一个生成器,但是里面的代码暂时不会被执行)
先来看一段代码
def demo(): #定义一个生成器函数 for i in range(3): yield i g=demo() #生成器函数调用产生一个生成器,要知道生成器其实也是迭代器的一种,也是可迭代的对象!! g1=(i for i in g) #使用生成器表达式产生了一个生成器,但是里面的代码暂时还不执行 g2=(i for i in g1) #同上 print(list(g1)) print(list(g2)) #这里使用强制类型转换将一个生成器转为一个list,强行加载生成器里的值到列表,会触发生成器里里面的代码
先来想一下,这段代码执行的结果是什么?
先分析一下代码的执行流程:
首先定义了一个生成器函数,然后调用该生成器函数,返回一个生成器g,接下来使用两个生成器表达式产生两个生成器g1,g2, 至此,上面生成器函数内的代码都没有被执行,知道list(g1)强制类型转换才会触发去执行g1生成器,g1执行生成器表达式中的for循环,依赖于生成器g,然后g开始执行生成器函数demo内的代码,拿到0给g ,再给g1 ,然后执行下一个for 循环,再从g中取值,g再去执行demo函数内的代码,拿到一个1,,,,最后g1会拿到0,1,2,3然后给list(g1)返回一个list=[0,1,2,3]-----------也就是第一个print()语句打印的内容~
然后list(g2)开始出发g2这个生成器,但是g2是从g1这个生成器拿值的,可是在刚才的分析中g1这个生成器已经取值取完了,所以拿不到值了,所以list(g2)返回的就是一个空列表;
这里需要注意,生成器函数一旦调用产生一个生成器,它只能从头到尾执行一次,而且是惰性的,你要(碰到for i in g 或者g.__next__() 或者强制类型转换list(g)三种情况下)我才会取值;
运行结果:
但是如果代码这样写呢?
def demo(): for i in range(4): yield i g=demo() g1=(i for i in g) g2=(i for i in g1) print(list(g)) print(list(g1)) print(list(g2))
其实很明显,就是list(g)的时候,g这个生成器已经去执行生成器函数内部的代码 去拿值了,所以到下一个list(g1)时,找g1生成器,执行生成器表达式的代码,然后依赖于g 发现g已经取值完毕,所以后续的在也拿不到值了~~
面试题2
def add(n,i): #定义了一个普通函数 return n+i def test(): #定义了一个生成器函数 for i in range(4): yield i g=test() #调用生成器函数,产生一个生成器 for n in [1,10]: g=(add(n,i) for i in g) print(list(g))
这段代码的执行结果又是什么呢?
先来分析一下,首先定义了一个普通函数,然后定义了一个生成器函数,进行生成器函数的调用返回一个生成器g,以上生成器函数内的代码一句也没有被执行,接下来一个for循环,每次执行一个for循环都使用列表生成式建立一个生成器,但是生成器表达式和定义生成器函数一样的,里面的代码都不会被执行,知道最后一句话list(g)才开始触发:
其实上面的for循环可以这样来理解:
n=1 g=(add(n,i) for i in g) n=10 g=(add(n,i) for i in g) list(g)
这个list(g)中的g其实会去找第二个生成器表达式产生的生成器g去拿值,然后里面的for循环中的g其实时第一个生成器表达式产生的生成器,而第一个生成器表达式内的for循环中的g其实是最上面定义的生成器函数调用产生的生成器,于是可以写成:
g=(add(n,i) for i in (add(n,i) for i in test()))
这里的n都是10
运行结果:
如果代码改成这样呢,执行结果又是什么呢?
def add(n,i): return n+i def test(): for i in range(4): yield i g=test() for n in [1,10,5]: g=(add(n,i) for i in g) print(list(g))
list(g)时才会触发生成器函数或者生成器表达式内的代码,执行流程如下:
n=1 g=(add(n,i) for i in g) n=10 g=(add(n,i) for i in g) n=5 g=(add(n,i) for i in g) g=(add(n,i) for i in (add(n,i) for i in (add(n,i) for i in test())))
运行结果: