import time print(time.time()) #执行结果 1533473443.1654115 #这个结果是从1970年到如今的每一秒 def fun(): start = time.time() #定义一个初始时间 time.sleep(1) #由于就打印一句话,这个时间差是计算不出来的,让函数停1秒,模拟函数执行时间 print('hello python!!!') #假如我这里是要打开某个文件,读取里面的内容 end = time.time() #定义一个结束时间 print(end - start) #用结束减去开始的时间,就是程序执行的时间 fun() #执行结果 # hello python!!! # 1.000720739364624 #能够看到花了这么长时间 这是一个函数,若是是代码里面有100个函数,我每个函数都须要加这个,并且这个只是我想看执行时间而已,看完以后确定是会删除掉的,这个时候就须要一个能在外部直接计算函数时间的函数 import time def time1(t): #咱们在外面定义一个函数,吧以前计算函数执行时间差的放外面来 start = time.time() t() #经过t这个位置参数才传参 end = time.time() print(end - start) def fun(): time.sleep(1) print('hello python!!!') time1(fun) #经过调用函数来计算fun函数计算的时间 # 执行结果 # hello python!!! # 1.0004518032073975 这个方式仍是存在问题,100个函数,我每次都要单独列出函数名来计算,意味着我要time1100遍 import time def fun(): time.sleep(1) print('hello python!!!') def fun1(): time.sleep(1) print('hello java!!!') def time1(t): def time2(): #经过闭包的用法,而此处的time1就是一个装饰器函数 start = time.time() t() #被装饰的函数 end = time.time() print(end - start) return time2 #这个地方必定不能加括号,若是是time2这样,就等于调用函数了。 fun2 = time1(fun) fun2() fun2 = time1(fun1) #这样fun2能够接收任意time1的参数(函数执行时间)并打印 fun2() #执行结果 hello python!!! 1.0199263095855713 hello java!!! 1.0145087242126465
在不断的学习过程当中,咱们的代码会愈来愈多,这个时候咱们想计算出代码执行的时长,就可使用到装饰器。html
在实际的生产中,每位程序员都须要相互协做,这就颇有可能你开发的函数会被别人调用,这样一来你的函数就等于封板的函数,若是须要调整确定是须要申请的,为了避免改变原有函数的调用方式,还想在原来的函数先后添加功能 ,就可使用到装饰器,这样经过闭包的装饰器来调用先后的函数完成不改变原有函数功能的状况下实现其它功能。java
开放封闭原则python
开放:对扩展是开放的程序员
封闭:对修改是封闭的web
import time def time1(t): def time2(): #经过闭包的用法,而此处的time1就是一个装饰器函数 start = time.time() t() #被装饰的函数 end = time.time() print(end - start) return time2 @time1 #在此处加上@time1就等于下面fun = time1(fun)这个赋值操做,全部@time1更加方便好用 #语法糖的必定是@装饰名,语法糖下面是你被装饰的函数,这样就造成了一个语法糖 def fun(): time.sleep(1) print('hello python!!!') #fun = time1(fun) fun() 执行结果 hello python!!! 1.012437105178833
import time def time1(t): def time2(): start = time.time() t() end = time.time() print(end - start) return time2 @time1 def fun(): time.sleep(1) print('hello python!!!') #在被装饰的函数里面是没有参数和返回值的 #fun = time1(fun) fun() 咱们给被装饰的函数加上返回值 import time def time1(t): def time2(): start = time.time() t() end = time.time() print(end - start) return time2 @time1 def fun(): time.sleep(1) print('hello python!!!') #在被装饰的函数里面是没有参数和返回值的 return 'java' #咱们在被装饰的函数里面return一个返回值 #fun = time1(fun) ret = fun() #咱们将函数赋予一个变量 print(ret) #打印变量的指 # 执行结果 hello python!!! 1.0013034343719482 None # 能够看到并无打印咱们返回内容,返回了一个空 这个是由于被装饰的fun函数已经被@time1给调用了,而且改变了他的值,刚好上面的time2在调用fun的时候是没有拿fun的return的值,并且time2本身自己也没有返回值,致使time2调用结束就没有返回任何值 调整time2调用逻辑 import time def time1(t): def time2(): start = time.time() ret = t() #并把ret的内容给到t()便可 end = time.time() print(end - start) return ret #为了下面的ret = fun()能拿到time2里面的内容,首先要return,让return拿到上面t()执行的结果 return time2 @time1 def fun(): time.sleep(1) print('hello python!!!') return 'java' #fun = time1(fun) ret = fun() #咱们要保证这个fun()是执行的time2里面的内容便可 print(ret) 执行结果 hello python!!! 1.0036890506744385 java
import time def time1(t): def time2(a): #装饰器函数里面也要加上 start = time.time() ret = t(a) #被装饰的函数也要加上 end = time.time() print(end - start) return ret return time2 @time1 def fun(a): #必定要在函数加上位置参数 time.sleep(1) print('hello python!!!',a) #若是是想在函数里面加参数 return 'java' #fun = time1(fun) ret = fun(2) print(ret) 执行结果 hello python!!! 2 1.0001533031463623 java 可是上面的记过只能解决一个参数的状况,若是是不固定的参数或者按照关键字传参,装饰器也要跟着改很麻烦 import time def time1(t): def time2(*args,**kwargs): #装饰器函数里面也要加上 start = time.time() ret = t(*args,**kwargs) end = time.time() print(end - start) return ret return time2 @time1 def fun(a,b): #必定要在函数加上位置参数 time.sleep(1) print('hello python!!!',a,b) #若是是想在函数里面加不少参数 return 'java' #fun = time1(fun) ret = fun(2,b = 1) print(ret) 执行结果 hello python!!! 2 1 #经过*args和**kwargs就能处理全部的参数 1.0002832412719727 java
import time def login(t): #1:装饰的名字更改 #2:若是定义一个装饰器可使用wrapper_函数名 #3:装饰器()这个括号里面永远是被装饰的函数 def time2(*args,**kwargs): #4:若是装饰器的内部函数,下面的必定要返回; #5:内部函数穿进来的动态参数 #7:此处是被装饰函数以前完成的事情 ret = t(*args,**kwargs) #5:这个地方必定要原封不动的返回 #7:被装饰函数以后完成的事情 return ret #6:且被装饰的函数必定要原封不动的返回 return time2 #4:且返回的函数名是不能带括号的 @login #1:语法糖也要更改 def fun(a,b): #8:此处有参数 time.sleep(1) print('hello python!!!',a,b) return 'java' fun = login(fun) #8:此处也要给参数
用装饰器把函数执行的结果记录到一个文件 def recorder(func): def inner(*args,**kwargs): with open('diary.txt','a',encoding='utf8')as f: f.write(func.__name__+'\n') #经过__name__将函数名记录下来 ret = func(*args,**kwargs) return ret return inner @recorder def diary(): print('周一天气晴') @recorder def diary1(): print('周二天气阴') diary() diary1() 执行结果: 周一天气晴 周二天气阴 diary.txt文件内容 diary diary1
#网页缓存装饰器,(有缓存就在本地打开,没有在网页加载) 编写思路: 1:首先须要导入os文件操做模块和网页处理相关的模块 2:写函数体和按照固定模式把装饰器写好 3:开始进行符合内容的需求编写,本地有文件,那咱们须要建立一个文件用来存放网页内容 4:本地有网页内容了,咱们须要去判断网页内容在本地是否存在,可是文件是咱们手动建立的,不是程序进行建立的,判断文件名不符合逻辑,须要判断文件是否为空 (判断文件的大小)便可。 5:怎么区分是网页读取的仍是本地的,须要给本地的加上一个标记,便于区分 import os from urllib.request import urlopen def cache(func): def inner(*args,**kwargs): if os.path.getsize('web_cache'): #os.path.getsize判断文件大小 with open('web_cache','rb')as f: return f.read() ret = func(*args,**kwargs) with open('web_cache','wb')as f: f.write(b'***'+ret) #(b'***'+ret) 给本地读取的问价加上标记 return ret return inner @cache def get(url): code = urlopen(url).read() return code ret = get('https://www.autohome.com.cn/beijing/') print(ret) ret = get('https://www.autohome.com.cn/beijing/') print(ret) 执行结果 -0-0-0-0-1.html#pvareaid=3311459" class="more">\xb8\xfc\xb6\xe0 ></a>\r\n b'***\r\n\r\n<!DOCTYPE html>\r\n\r\n<html>\r\n<head>\r\n #本地文件
♣二:装饰器的进阶缓存
def Thunder_shower(): ''' 若是是我想打印函数的名字Thunder_shower :return: ''' print('今天局部雷阵雨') print(Thunder_shower.__name__) #使用__name__方法就能够打印函数的名字,而且是字符串的形式 print(Thunder_shower.__doc__) #doc方法是答应函数里面的注释内容 执行结果: Thunder_shower 若是是我想打印函数的名字Thunder_shower :return:
def wrapper(func): def inner(*args,**kwargs): ret = func(*args,**kwargs) return ret return inner @wrapper def holiday(day): print('今天节假日'%day) return '周六' print(holiday.__name__) #若是是装饰器,我在外面使用打印函数名的方法打印的是装饰器里面函数的名字 执行结果 inner 那若是我只须要看到我函数名,不须要看到装饰器名字,可使用下面的方法 from functools import wraps #可使用from functools import wraps def wrapper(func): @wraps(func) #在装饰器里面在装饰下函数,以前咱们使用__name__打印的是inner,咱们在inner上层装饰func便可正常打印被装饰的函数名 def inner(*args,**kwargs): ret = func(*args,**kwargs) return ret return inner @wrapper def holiday(day): '''这是一个放假通知''' print('放假%s天'%day) return '周六' print(holiday.__name__) print(holiday.__doc__) ret = holiday(6) print(ret) 执行结果 holiday #能够看到函数名被打印 这是一个放假通知 #函数里面的注释经过__doc__方式也打印出来了 放假6天 周六
计算函数执行时间的装饰器,若是是幻术有100个,前面已经加好了函数执行的时间,而且去使用的语法糖 ,若是是后面我要删除这个装饰器,会显得极为麻烦,由于你须要注释或删除100个语法糖,若是咱们使用带参数的装饰器就能够在外面给装饰器传递一个参数,至关于一个开关,当开关开启我就执行计算运行时间装饰器,关闭就不计算,先后不影响函数的使用过程,这个就是咱们要达到目的。闭包
import time FLAGE = True def timer_out(flage):#1:下面的@timer_out(会传一个FLAGE的参数回来) def timmer(func): #3:装饰器按照原来的方式执行了 def inner(*args,**kwargs): if flage: #4:到这里开始判断,等于True我就执行我下面的代码 start = time.time() ret = func(*args,**kwargs) end = time.time() print(end-start) return ret else: #5:不然,就是等于False,就执行else后面的代码 ret = func(*args,**kwargs) return ret return inner return timmer #2:执行到这里的时候我return的是timmer,就等于我又执行了@timmer @timer_out(FLAGE) #此装饰器的精髓就在此处:@timer_out==@timmer @timmer == timmer == eggs1(kkkk) #以前函数执行的方式是调用语法糖@timmer这样去执行,在上面能够看到我在原装饰器全部代码不变的状况下 #加了几行,这个里面包含开始的FLAGE = True,中间的if和else行,这个是怎么执行的了,以前的装饰器肯 #是要按照它以前的执行方式来的,及@timmer == timmer == eggs1(kkkk)这个函数,那么加了timer_out就 #在等号前面又加了一个等号,及@timer_out==@timmer @timmer == timmer == eggs1(kkkk)这样就又执行 #到原来装饰器的语法糖了。 def eggs1(): time.sleep(0.02) print('kkkkk') @timer_out(FLAGE) def eggs2(): time.sleep(0.02) print('hahahha') eggs1() eggs2() 等于True的执行结果: kkkkk 0.02007269859313965 hahahha 0.020559310913085938 等于Flase的状况: import time FLAGE = False def timer_out(flage):#1:下面的@timer_out(会传一个FLAGE的参数回来) def timmer(func): #3:装饰器按照原来的方式执行了 def inner(*args,**kwargs): if flage: #4:到这里开始判断,等于True我就执行我下面的代码 start = time.time() ret = func(*args,**kwargs) end = time.time() print(end-start) return ret else: #5:不然,就是等于False,就执行else后面的代码 ret = func(*args,**kwargs) return ret return inner return timmer #2:执行到这里的时候我return的是timmer,就等于我又执行了@timmer @timer_out(FLAGE) #此装饰器的精髓就在此处:@timer_out==@timmer @timmer == timmer == eggs1(kkkk) #以前函数执行的方式是调用语法糖@timmer这样去执行,在上面能够看到我在原装饰器全部代码不变的状况下 #加了几行,这个里面包含开始的FLAGE = True,中间的if和else行,这个是怎么执行的了,以前的装饰器肯 #是要按照它以前的执行方式来的,及@timmer == timmer == eggs1(kkkk)这个函数,那么加了timer_out就 #在等号前面又加了一个等号,及@timer_out==@timmer @timmer == timmer == eggs1(kkkk)这样就又执行 #到原来装饰器的语法糖了。 def eggs1(): time.sleep(0.02) print('kkkkk') @timer_out(FLAGE) def eggs2(): time.sleep(0.02) print('hahahha') eggs1() eggs2() 执行结果: kkkkk hahahha 总结:为何会执行,这个是利用了装饰器是一个闭包函数的原理,以前提过闭包函数能够调用外部的变量,带参数的装饰器也是利用了这个原理
def eggs1(func): #2:先执行eggs1装饰器(放内存) def inner1(): print('eggs,123456') func() print('eggs1,654321') return inner1 def eggs2(func): #:4:执行eggs2装饰器(放内存) def inner2(): print('eggs2,123456') func() print('eggs2,654321') return inner2 @eggs2 #2:f=eggs2(f)此时的eggs2执行的时候结果是eggs1执行以后的结果,也就是eggs2(inner1)=inner2 @eggs1 #1:先执行,f=eggs1(f)==inner1 #执行eggs1函数,由于装饰器语法糖只能找到离他最近的函数去执行,这个就是此函数的转折点。 def f(): print('in f') f() #执行结果: eggs2,123456 eggs,123456 in f eggs1,654321 eggs2,654321
这个装饰器的用法能够用于,连续登陆次数计算,超过锁定的功能,例如客户登录,确定是先登录在计算次数,可是我在外面加上一个次数限制,限制5次就锁定,那么用户在登陆以前就须要判断次数了,而不是客户登录的过程当中再去判断次数,这样实际需求更加合理。app
先说明一个小知识点,咱们日常在使用xxx.这样的时候,发现只要是带点就能够出来好多方法,其中你能够看到好多__xxx__双下划线的方法,这些带双下划线的方法咱们叫“双下方法”,其实咱们写代码的时候直接写1+2这样的代码,执行,python就能执行并计算出结果,咱们就觉得计算机能识别+,-,*,/这样的符号,其实计算机是不能识别这种符号的,可是为何能执行是由于其实咱们执行1+2的时候,python解释器会进行识别,你是要执行加法运算,那么我直接去调用__xxx__这样的方法去执行,而后返回一个结果给你。ide
print(dir([])) print([1]+[2]) == print([1].__add__([2])) #执行结果 ['__add__', '__class__', '__contains__', '__delattr__', 。。。。。 [1, 2] [1, 2] 能够看到上面第一行代码执行的结果,会出来好多方法 上面第二行出来来的结果是一致的 第二行的执行过程就是当python解释器读到+号的时候就去调用内部的__and__ 方法,而后把后面的[2]传进来,获得结果返回给你,执行方式其实就函数,只 不过这个函数是别人用c语言给你写到集成到python里面去了。
在前面的基础部分,列表,字典,元祖等均可以在python里面调出它的方法,使用方法就是print便可。函数
print(set(dir([]))&set(dir({}))&set(dir(''))&set(dir(range(10)))) #求这些类型的共同方法 #执行结果: #{'__init_subclass__', '__ge__', '__reduce_ex__', '__class__', '__iter__', '__str__', '__init__',。。。。 #其中有一个双下方法__iter__这个方法,它就是iterable(迭代)英文的简写 print('__iter__' in dir(int)) print('__iter__' in dir(bool)) print('__iter__' in dir(list)) print('__iter__' in dir(dict)) print('__iter__' in dir(set)) print('__iter__' in dir(range(1))) 执行结果 False False True True True True 结论:就是只要能被for循环的都会有__iter__方法 for i in 123: pass # 执行结果: Traceback (most recent call last): File "C:/pycharm_fill/mg_迭代器.py", line 31, in <module> for i in 123: TypeError: 'int' object is not iterable # 能够发现是报错的,报错内容里面有一个单词就是iterable,说明这个123是不能循环的
经过上面的咱们得出只要是打印方法出来带__iter__方法都是可迭代的且均可以被for循环,另外只要有__iter__方法就必须遵照可迭代协议。
#__iter__的__next__方法: k = ['a',1,'wedw'] iter1 = k.__iter__() print(iter1.__next__()) print(iter1.__next__()) print(iter1.__next__()) 执行结果: a 1 wedw
既然上面的得出结论[].__iter__()就是一个迭代器,那么__next__方法就能够在迭代器里面一个一个取值。
上面咱们整理了这么多最后就指向了一个方法就是__iter__和,那么只要是带这个方法的就是迭代器,也定义了咱们若是是本身写的代码包含__iter__和__next__方法就是一个迭代器
并且这两个方法少一个都不行。
print('__iter__' in dir([].__iter__())) print('__next__' in dir([].__iter__())) 执行结果: True True 说明列表的方法里面iter和next方法 from collections import Iterable #Iterable【迭代器】 from collections import Iterator #Iterator【可迭代】 print(isinstance([],Iterable)) print(isinstance([],Iterator)) 执行结果 True #是一个迭代器 False #不是一个可迭代对象 from collections import Iterable #Iterable【迭代器】 from collections import Iterator #Iterator【可迭代】 class a: def __iter__(self):pass def __next__(self):pass k = a() print(isinstance(k,Iterable)) #isinstance用于检查是否有特定的方法 print(isinstance(k,Iterator)) 执行结果 True True from collections import Iterable #Iterable【迭代器】 from collections import Iterator #Iterator【可迭代】 class a: def __iter__(self):pass #def __next__(self):pass #注释next k = a() print(isinstance(k,Iterable)) print(isinstance(k,Iterator)) 执行结果 True #对iter没有影响 False from collections import Iterable #Iterable【迭代器】既知足迭代器协议(iter&next) from collections import Iterator #Iterator【可迭代】既知足可迭代协议(iter) class a: #def __iter__(self):pass #注释iter方法 def __next__(self):pass k = a() print(isinstance(k,Iterable)) print(isinstance(k,Iterator)) 执行结果 False False #结果next也不能用了,结果说明next是依托于iter
由此也得出了迭代器协议,内部包含iter方法和next方法的就是迭代器
print([].__iter__()) # 执行结果 # <list_iterator object at 0x00000221B9B128D0> # 一种就是在打印结里面明确告诉你是一个iterator的时候 #第二种就就是后面直接给你返回了内存地址的有多是迭代器 #第三种,能够被for循环 print(range(15)) # 执行结果; # range(0, 15) # 这种看似没有返回什么可用的信息,也有多是一个迭代器 总之要想知道是不是迭代器能够去判断他它,固然判断的结果也就证实了它是否能够被循环 print('__iter__' in dir(int))
迭代器的优点:
1:for循环的本质就是在带内部的迭代器方法在取值,全部你会以为for比while好用,由于你不用关心你取的值都在什么地方,一个个的去取,直到取完为止。
2:节省内存空间,上面咱们用到了range()方法,为何就只能打印两个数,若是你将range赋值给list,你会发现比较慢,到了必定数目就会超出内存报错,其实就是节省内存加快处理致使的,而for循环会随着每次循环逐一开辟内存空间,并且咱们每次写循环都会写for循环,没有说迭代器循环,这个是由于单纯写迭代器循环可能会出现报错,for能够把这些报错内部处理了,全部后面写代码不须要出现iter和next方法,用for就行。
迭代器的缺点:
1:上面说迭代器其中一个好用的点就是内存的使用机制,但同时也是这个内存使用机制也致使了迭代器比较局限,例如我不想开辟一大块内存空间,想用的时候随时去调用它取值,这个时候迭代器 就有局限性了,固然可使用函数,装饰器能解决,但仍是会很麻烦。
针对上面的缺点咱们就须要本身写迭代器,咱们本身写的迭代器都叫作生成器。
注意事项: 1:主要函数里面含有关键字yield,它就是一个生成器 2:yield和return同样不能在函数外面使用,且yield不能和return在一个函数里面出现,也就是不能共用一个函数 def generator(): print(1) yield 'a' ret = generator() print(ret) 执行结果 <generator object generator at 0x0000027F5BF18F68> 3:能够看到执行以后没有正常返回和打印我函数里面的值,而是执行后会获得一个生成器做为返回值 def generator(): print(1) yield 'a' ret = generator() #此处的ret就是生成器,而整个def函数就是生成器函数 print(ret) print(ret.__next__()) #上面咱们说了咱们写的迭代器就是生成器,反过来,咱们的生成器就含有迭代器的iter和next方法 执行结果 1 a
def generator(): #1:执行函数generator print(1) #4:打印1 yield 'a'#5:把a做为返回值给到ret print(2) yield 'b' ret = generator() #2:接下会执行到这里获取一个生成器 print(ret.__next__()) #3:执行打印,打印里面有next方法,那他就会返回到def generator从头开始执行 #6:最后打印,可是这个打印以后生成器函数不会结束。 # 执行结果 # 1 # a # 发现我上面的2和b没有执行。 def generator(): print(1) yield 'a' print(2) yield 'b' ret = generator() print(ret.__next__()) print(ret.__next__()) #只有在此print的时候2和b才能被执行 #若是你在print(ret.__next__())就会报错 执行结果 1 a 2 b 由此咱们能够得出,生成器函数能够去控制,能够在制定的位置中止 def generator(): print(1) yield 'a' print(2) yield 'b' ret = generator() for i in ret: print(i) 执行结果 1 a 2 b 上面既然是一个可迭代的函数,那么就可使用for,能够看到结果和我上面每次next执行结果一致,惟一不能控制的就是在哪里中止
# def generator(): # for i in range(100000): #打印10万个数据 # yield '每%s秒的数据'%i # k = generator() # count = 0 # for i in k: # count += 1 # print(i) # if count > 50: #我能够指定取数据 # break # # 执行结果 # # 每48秒的数据 # # 每49秒的数据 # # 每50秒的数据 # # print('*****',k.__next__()) #并且我还不用去改count > 50的值,生成器会帮忙记住我上次执行到哪里,我须要在哪里接着执行 # # 执行结果 # # ***** 每51秒的数据 # #按照上面的原理,我还能够接着取 # for i in k: # count += 1 # print(i) # if count > 100: #上下两个数据不会重复打印,是先取完上面的50,读到这儿继续取后面的50 # break # # 执行结果 # # 每97秒的数据 # # 每98秒的数据 # # 每99秒的数据 # # 每100秒的数据 #那上面咱们既然说带next方法的就是迭代器,相同的话for也能完成【续】取值的功能 l = [1,2,3,4,5] for i in l: print(i) if i == 2: break for i in l: print(i) 执行结果: 1 2 1 2 3 4 5 会看到前面1,2的for执行完以后,第二个for是从头开始的,这个是由于你每执行一个for都是使用到了迭代器方法,可是都是在for内部执行的,你下面的for 和你上面的for没有关系,同理生成器1和生成器2是没有关系的
经过一个函数去实时监听一个文件,当文件内容更新实时给返回到屏幕上。
def tail(filename): f = open(filename,encoding='utf8') while True: line = f.readline() if line.strip(): yield line.strip() k = tail('file') for i in k: print(i)
def generator(): print(123) counter = yield 'a' #正常函数执行到这里就会经过yield将指返回,可是我在 #下面使用了send方法,这个方法利用了yield会暂停的特色 #而后把我send的指接收,以后再继续执行下面的代码 print('****',counter) print(456) yield 'b' k = generator() ret = k.__next__() print(ret) ret = k.send('789') #send能够在下一个yield以前给传递一个参数执行接收以后,在继续执行个人代码,send和next的效果同样 print(ret) # 执行结果: # 123 # a # **** 789 # 456 # b
send的效果和next的方法基本一致,只是在获取下一个值的时候,给上一个值的位置传递一个数据
send的注意事项:
1:第一次使用生成器的时候,第一个执行必须使用next以后才可使用send
2:最后一个yield不能接受外部的指,也就是不能使用send方法,若是要使用,请保证你的send不是在最后的一个yield上去执行,能够在最后用一个yield收尾。
def generator(): print(123) counter = yield 'a' print('****',counter) print(456) yield 'b' ret = yield 'c' yield #在最后使用yield收尾,哪怕返回空值
因此send的基本用法就是在开始next和yield结尾之间来完成外部数据的传递
需求标题是用户调用函数传值,将拿到的数字结合前面的数字计算平均值,公式为:平均值=数字和/个数
def average(): sum = 0 count = 0 avg = 0 while True: num = yield avg sum += num count += 1 avg = sum/count avg1 = average() avg1.__next__() avg2 = avg1.send(20) avg2 = avg1.send(76) print(avg2) avg2 = avg1.send(24) print(avg2) 执行结果 48.0 40.0
例若有一个字符串,字符串的个数足够大,那要读这个字符串可能就须要一批一批的读,而后一个个的返回。
# #常规取值的方法: # def wget(): # a = 'qaz' # b = '889' # for i in a: # yield i # for i in b: # yield i # w = wget() # for i in w: # print(i) # #执行结果 # # q # # a # # z # # 8 # # 8 # # 9 # # #yield from版本 # def wget(): # a = 'qaz' # b = '889' # yield from a #yield from是在python3里面新加的功能,他主要的做用是可以 # 让你在一个容器类型数据里面集体返回,而后下面去一个一个接收 # yield from b # w = wget() # for i in w: # print(i) # #执行结果 # q # a # z # 8 # 8 # 9
♣五:生成器表达式和各类推导式
生产器表达式和列表推导式很类似,最直观的就是中括号换成了园括号 k = (i for i in range(3)) print(k) for i in k: print(i) #执行结果 <generator object <genexpr> at 0x000001DFE8718F68> 0 1 2 1:能够看到括号是有区别的 2:返回值不同,能够看到直接print生成器是不能直接拿到指的 3:节省内存空间 4:功能单一,不能适用于全部的需求
wat_list = ['西瓜%s'%k for k in range(3)] print(wat_list) #执行结果 ['西瓜0', '西瓜1', '西瓜2'] 能够看到若是是咱们写这样的代码的时候应该是须要append来完成的 # for k in range(10): # wat_list.append('习惯%s'%k)#正常是须要一个append的 # print(wat_list) 那为何上面咱们没有使用append就能够完成,是由于上面这个是一个列表推导式 for循环每次循环都会拿到一个指,你想这个循环获得的指放到这个列表里是以什么样的形式 [i for i in xxx],这个里面for前面的i加上先后的中括号就是列表推导式,而后你打印出来就行 print([i for i in range(10)]) #执行结果 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
咱们只要学会了列表推导式,能够把咱们以前不少代码简化 例1: print([i*2 for i in range(10)]) #执行结果 [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] 例2: print([i*i for i in range(10)]) #执行结果 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] 例3: print([i/2 for i in range(10)]) #执行结果 [0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5] 例4: print([i%2 for i in range(10)]) #执行结果 [0, 1, 0, 1, 0, 1, 0, 1, 0, 1] 是否是会以为有些代码很简单,好比你要判断计算结果是否为0,为0的数字打印出来等
列表推导式的语法
1:变量名=[遍历循环的结果 for i in 可迭代元素] #遍历基本法 2:变量名=[删选以后的结果 for i in if 元素和条件] #删选基本法
# 50之内能被9整除的数字 ret = [i for i in range(50) if i%9==0] print(ret) # 执行结果 # [0, 9, 18, 27, 36, 45] #50之内能被9整除数字的平方 ret = [i*2 for i in range(50) if i%9==0] print(ret) #执行结果 [0, 18, 36, 54, 72, 90] # # 50之内大于20能被9整除数字的平方 ret = [i*2 for i in range(50) if i>20 if i%9==0] print(ret) # 执行结果: # [54, 72, 90]
键值对互换 mac = {'a':10,'b':20} mac1={mac[i]:i for i in mac} print(mac1) 执行结果 {10: 'a', 20: 'b'}
mac = {x*x for x in [4,4,2]} print(mac) # 执行结果 # {16, 4} # 这个里面利用了集合自带的去重功能 # 4*4=16,4*4=16 两个值计算的结果同样,重复了,去掉重复的,只显示一个
上面咱们看到各类推导式,这些推导式就知足筛选基本法和遍历基本法,并且这些推导式均可以把相应括号换成(圆括号),就能够变成生成器表达式,并且实际生产中列表推导式比较多,另外的两个相对比较少。