Day12 of learning python--迭代器进阶及生成器
1.*args和**kwargs的使用
调用函数是进行打散操作,函数的行参是聚合操作
1 def outer(*args): #聚合 2 print(args) #(1,2,3,4) 3 print(*args) #打散 # 1,2,3,4 4 def inner(*args): #传输参数是聚合 5 print('inner:',args) #inner:(1,2,3,4) 6 inner(*args) #调用是打散 7 8 outer(1,2,3,4) # outer(*[1,2,3,4]) outer(*(1,2,3,4))
2.readline(),readlines()的区别
readline(),一行一行地读,readlines(),每一行当成列表中地一个元素,添加到List中,且元素后带有换行符‘\n’,‘\r’是回车键的意思
1 f = open('E:\log.txt',mode='r+',encoding='gbk') 2 line = f.readline().strip() #一行一行地读 3 print(line) 4 line = f.readlines() #每一行当成列表中地一个元素,添加倒list中 5 print(line)
3. wraps的使用
wraps的作用是,因为语法糖的原因,原函数名的func已经不存在于全局了,而是存放了inner的地址了。而wraps是能够重新获取原函数的__doc__,__name__
1 from functools import wraps 2 import time 3 def timmer(f): 4 @wraps(f) #没有这个话,原来函数名func已经不存在于全局了,而是存放了inner的地址了 5 def inner(*args,**kwargs): 6 start = time.time() 7 ret = f(*args,**kwargs) 8 end = time.time() 9 print(end-start) 10 return ret 11 return inner 12 13 @timmer 14 def func(a,b): 15 ''' 16 这个是问候语 17 :param a: 18 :param b: 19 :return: 20 ''' 21 time.sleep(0.01) 22 print('老板好,大家好',a,b) 23 return '新年好' 24 25 print(func.__name__) #查看字符串格式的函数名, func 26 print(func.__doc__) #docunment 27 re = func(1,2) 28 print(re)
4.装饰器的进阶
装饰器的作用是:在不改变原函数的调用方式的情况下,在函数的请后添加功能,本质是:闭包函数
三层装饰器,应用例子:如果有500个函数,都添加了语法糖,如果要删除这个功能,得一个一个得去删除。但是三层装饰器在外部定义一flag标志符,可以控制装饰器添加的内容不生效
1 mport time 2 FLAG = False 3 def timmer_out(flag): #用于传入flag 4 def timmer(func): # 装饰器 5 def inner(*args,**kwargs): #闭包函数,用于装饰功能 6 if flag: #如果flag是真的,则执行起到装饰的代码,否则则,执行原函数体 7 start = time.time() 8 ret = func(*args,**kwargs) 9 end = time.time() 10 print(end-start) 11 return ret 12 else: 13 ret = func(*args, **kwargs) 14 return ret 15 return inner 16 return timmer 17 18 @timmer_out(FLAG) #先执行@右边的,timmer_out(FLAG) == timmer @timmer == wahaha =timmer(wahaha) 19 def wahaha(): 20 time.sleep(0.1) 21 print('wahahahahahah') 22 23 @timmer_out(FLAG) 24 def ergoutou(): 25 time.sleep(0.1) 26 print('erguotoutoutou') 27 28 wahaha() 29 ergoutou()
多个装饰器装饰一个函数
1 def wrapper1(func): # func -->f 2 def inner1(): 3 print('wrapper1,before func') 4 func() 5 print('wrapper1,after func') 6 return inner1 7 8 def wrapper2(func): # func -->inner1 9 def inner2(): 10 print('wrapper2,before func') 11 func() 12 print('wrapper2,after func') 13 return inner2 14 15 @wrapper2 # f = wrapper2(inner1) -->inner2 16 @wrapper1 # f = wrapper1(f) -->inner1 17 def f(): 18 print('in f') 19 20 f() #inner2()
结果:
wrapper2,before func
wrapper1,before func
in f
wrapper1,after func
wrapper2,after func

和俄罗斯的套娃娃一样,注意的是执行的先后顺序
5.生成器
生成器--迭代器
生成器函数--本质上就是自己写的函数
定义:只要含有yield关键字的函数都是生成器函数,而且不能和return公用,二期只能用于函数内部
1 def generator(): 2 print(1) 3 yield 'a' 4 #生成器函数:执行之后会得到一个生成器作为返回值,就是一个迭代器 5 ret = generator() 6 print(ret) 7 print(ret.__next__()) #触发生成器的函数体
执行函数体的时候,遇到yield,不会退出函数。
1 def generator(): #生成器函数 2 print(1) 3 yield 'a' 4 print(2) 5 yield 'b' 6 yield 'c' 7 g = generator() #g是生成器 8 # print(g) 9 # print(g.__next__()) 10 # print(g.__next__()) 11 # print(g.__next__()) 12 for i in g: 13 print(i) # 一个一个触发yield的返回值
结果:1 a 2 b c
假如我我想定义一个函数,打印200万个哇哈哈,那么一般的方方法会消耗很多的内存资源,用生成器就可以解决了
#娃哈哈%i def wahaha(): for i in range(200000): yield 'wahahah%s'%i g = wahaha() for i in g: # 一边生成一边打印,打印完了前一个,就不存在于内存当中了 print(i)
for i in g:
print(i) #从上个for的yield继续往后面打印
注意,列表是一个迭代对象,但执行多个for的时候,每个for生成的迭代器都是一个新的,不同的
1 l = [1,2,3,4,5] # 列表是一个可迭代对象 2 for i in l: # 遇到for,在内部转换成一个迭代器 3 print(i) 4 if i == 3: 5 break 6 7 for i in l: # 重新转换成一个迭代器 8 print(i) 9 10 for i in l: 11 print(i)
监听文件输入的例子
1 def tell(filename): 2 f = open(filename,'r',encoding='gbk') 3 while True: # for循环只能读存在的,不能读新写,而且不能操作 4 line = f.readline() 5 if line.strip(): # strip(),默认去掉空格,换行符。或者去掉特定字符串 6 yield line.strip() 7 8 g = tell('F:\hi.txt') # 该迭代器可以对文件中的内容进行操作 9 for i in g: 10 print('***',i)
6.作业讲解
1)编写装饰器,为多个函数加上认证的功能(用户的账号和密码来源于文件),要求登陆成功一次,后续的函数都无需再输入用户名和密码
1 flag = False 2 def dec(f): 3 def inner(*args,**kwargs): 4 global flag # 在函数内部定义全局变量,让局部函数影响全局变量 5 if flag == False: 6 username = input("请输入登陆名:") 7 password = input("请输入密码:") 8 with open('F:\hello.txt',mode='r+',encoding='gbk') as file: 9 if username == file.readline().strip() and password == file.readline().strip(): 10 flag = True 11 ret = f(*args, **kwargs) 12 return ret 13 else: 14 print("输入错误") 15 else: 16 ret = f(*args, **kwargs) 17 return ret 18 return inner 19 20 @dec 21 def shopping_add(): 22 print('增加一个物品') 23 24 @dec 25 def shopping_del(): 26 print('删除一个物品') 27 28 shopping_add() 29 shopping_del()
2)编写装饰器,为多个函数加上记录调用功能,要求每次调用函数都将被调用的函数名称写入文件
1 def remmber(f): 2 def inner(*args,**kwargs): 3 ret = f(*args,**kwargs) 4 with open('F:\hao.txt','a',encoding='gbk') as file: 5 file.write(f.__name__+'\n') 6 return ret 7 return inner 8 9 @remmber 10 def shopping_add(): 11 print('增加一个物品') 12 13 @remmber 14 def shopping_del(): 15 print('删除一个物品') 16 17 shopping_add() 18 shopping_del() 19 with open('F:\hao.txt','r',encoding='gbk') as f1: 20 k = f1.read() 21 print(k)
3)编写下载网页内容的函数,要求功能是:用户传入一个URL,函数返回下载页面的结果,
编写装饰器,实现缓存网页内容的功能,具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),就优先从文件中读取网页内容,否则,就去下载
1 from urllib.request import urlopen 2 import os 3 def cache(f): 4 def inner(*args,**kwargs): 5 if os.path.getsize('F:\hello.txt'): 6 with open('F:\hello.txt', 'rb') as file: 7 return file.read() 8 ret = f(*args,**kwargs) 9 with open('F:\hello.txt','wb') as file: 10 file.write(b'***'+ret) 11 return ret 12 return inner 13 @cache 14 def get(url): 15 code = urlopen(url).read() #得到的是一个bytes的代码 16 return code 17 18 ret = get('http://www.baidu.com') 19 print(ret) 20 ret = get('http://www.baidu.com') 21 print(ret) 22 ret = get('http://www.baidu.com') 23 print(ret)
浙公网安备 33010602011771号