【Python3_进阶系列_010】Python3-生成器
一、生成器
在Python中,使用生成器可以很方便的支持迭代器协议。生成器通过生成器函数产生,生成器函数可以通过常规的def语句来定义,但是不用return返回,而是用yield一次返回一个结果,在每个结果之间挂起和继续它们状态,来自动实现迭代协议。
下面通过几个实例来了解生成器的工作:
例子1:
def fun(n): i=0 while i<n: print("开始",i) yield i i+=1 print("结束",i) b=fun(5) next(b) next(b) 输出: 开始 0 结束 1 开始 1
执行过程:第一个next(b),执行到print(“开始”,0),遇到yeild就停止。第二个next(b),会从上一个yield之后开始执行,一直到下一个yield。也就是输出结束1,开始1.
特点1:函数里面加入yield之后,函数就是生成器
也就是说,yield是一个语法糖,内部实现支持了迭代器协议,同时yield内部是一个状态机,维护着挂起和继续的状态。
生成器函数返回生成器的迭代器。 “生成器的迭代器”这个术语通常被称作”生成器”。
要注意的是生成器就是一类特殊的迭代器。作为一个迭代器,生成器必须要定义一些方法,其中一个就是__next__()。如同迭代器一样,我们可以使用__next__()函数来获取下一个值。
在一个 generator function 中,如果没有 return,则默认执行至函数完毕,如果在执行过程中 return,则直接抛出 StopIteration 终止迭代。
实例2:生成器实现斐波那契数列
先看一下传统的方法: def fab(maxs): n,a,b = 0,0,1 while n < maxs: print(b) a,b = b,a+b n = n + 1 fib = fab(6) 一次性输出: 1 2 3 5 8
加入生成器: def fab(maxs): n,a,b = 0,0,1 while n < maxs: yield b ##yield只能依次读取,不能从中间读取 a,b = b,a+b n = n + 1 fib = fab(6) print(next(fib)) print(next(fib)) print(next(fib)) print(next(fib)) print(next(fib))
依次输出:
1
1
2
3
5
可以看到生成器实现的时候,我们可以按照需要进行取值,而不用一次性输出全部的数据。这个功能在读文件的时候,如果文件很大,我们可以用生成器去读,就不会占很大的内存空间
二、面试题
1.小数位步长实现:range函数的步长都是》=1的,我们实现一个函数,支持小数位的步长。例如 rangex(0,1,0.1).依次返回0,0.1,0.2,0.3.。。。
def range_powerfull(start,end,step): if isinstance(start,(int,float)) and isinstance(end,(int,float)): while start <end: start yield float(start) start+=step else: print('输入错误,开始和结束位置请输入整数或者浮点数') a = range_powerfull(0,1,0.1) b = range_powerfull(3,10,0.75) c = range_powerfull('c',5,0.23) for x in a: print(x) for y in b: print(y) 输出: 0.0 0.1 0.2 0.30000000000000004 0.4 0.5 0.6 0.7 0.7999999999999999 0.8999999999999999 0.9999999999999999 3.0 3.75 4.5 5.25 6.0 6.75 7.5 8.25 9.0 9.75
可以通过for循环一次全部取出值,也可以通过next()函数一个一个的取值。
2.
实现装饰器测试函数的运行时间,现在要求,在这个装饰器的基础上,完善这个装饰器。使其:
1. 依然可以测试函数运行的时间
2. 依然可以将函数运行的时间输出到屏幕上
3. 除了以上两点,还可以将运行时间,以日志的形式记录在指定的文件中(当作日志)。
4.测试函数大家自己选取
import time def run_time(func): def new_fun(*args): t0 = time.time() back = func(*args) times = time.time() - t0 print('run time: %s' % (times)) with open('log.txt', 'a+') as f: f.write('---%s\t' % (str(time.asctime(time.localtime())))) f.write('run time: %f\n' % (times)) return back, times return new_fun @run_time def bu(x): for i in range(len(x)): for j in range(i,len(x)): if x[i]>=x[j]: x[i],x[j]=x[j],x[i] return x print(bu([2,3,6,1,3,2,7]))
输出:
([1, 2, 2, 3, 3, 6, 7], 0.0)
并且追加写入log
3.在编辑文本中,我们经常需要在文本中找到某个模式出现的位置。比如我要在文本中找到某个字符串出现的次数和位置,这种问题称为字符串匹配问题。我们简化为在一个字符串中找到模式出现的位置。
如:字符串为:str1='adhvahabcabcabcfjiaohgio'
模式为:str2='abc'
找出str1中模式出现的位置(6,9,12)
str1='adhvahabcabcabcfjiaohgio' str2='abc' str11='das3212345mn*1232123)' str22='32123' def find_index(pattern,original): li = [] for i in range(len(original)): if original[i]==pattern[0] and original[i:i+len(pattern)]==pattern: li.append(i) return li print(find_index(str2,str1)) print(find_index(str22,str11))
输出:
[6, 9, 12]
[3, 15]
4.字符串里面的count可以统计字符出现的次数,现在要求大家定义这样的一个类,这个类里有一个方法可以统计字符串里的所有的字符出现的次数,并作为一个字典返回,同时这个类还有字符串的所有方法。
import os, hashlib class new_str(str): ##继承str就可以有字符串的全部方法 def __init__(self, str1): self.str1 = str1 def count(self): dic = {} for i in set(self): dic[i] = int(super().count(i)) return dic randstr = hashlib.sha1(os.urandom(32)).hexdigest() a = new_str(randstr) print(a.count())
输出:{'a': 1, '3': 3, '4': 2, '9': 3, '6': 2, 'f': 2, '7': 6, 'd': 3, '8': 2, 'c': 5, '1': 2, '0': 4, '5': 2, '2': 3}

浙公网安备 33010602011771号