装饰器讲解
-
示例
2. 编写装饰器,在每次执行被装饰函数之前打印一句’每次执行被装饰函数之前都得先经过这里,这里根据需求添加代码’ 3. 编写装饰器,在每次执行被装饰函数之后打印一句’每次执行完被装饰函数之后都得先经过这里,这里根据需求添加代码’ 4. 编写装饰器,在每次执行被装饰函数之前让用户输入用户名,密码,给用户三次机会,登录成功之后,才能访问该函数. 5. 编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件,只支持单用户的账号密码,给用户三次机会),要求登录成功一次,后续的函数都无需再输入用户名和密码 6. 编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件,可支持多账号密码),要求登录成功一次(给三次机会),后续的函数都无需再输入用户名和密码。 7. 给每个函数写一个记录日志的功能,
功能要求:每一次调用函数之前,要将函数名称,时间节点记录到log的日志中。 所需模块: import time struct_time = time.localtime() print(time.strftime("%Y-%m-%d %H:%M:%S",struct_time))
复习装饰器: 装饰器是干嘛的?有什么用? 统计爬虫函数的工作效率
import time def timmer(func): #func = 爬虫函数 def inner(): start =time.time() func() #func() = 爬虫函数的地址() ==>调用了爬虫函数 print(time.time()- start) #结果就是爬虫函数执行的时间 return inner def 爬虫函数(): '''爬虫的功能''' # 完成爬虫函数的基础上再完成一些新的功能 爬虫函数 = timmer(爬虫函数) #爬虫函数 = inner的地址 爬虫函数() #inner() --- # 不能紧耦合 因为拆分功能的时候容易出错 # 不能轻易改变代码的调用习惯 # 如果加上了装饰器,在调用“爬虫函数”的时候,实际上还调用了一个timmer的功能,那么没有改变用户的调用习惯,但是加上了新功能 --装饰器做的事儿 # a有一个装饰器b 如果调用a函数,不仅把a函数执行了,还要执行b函数中的代码 --- --- #在调用爬虫函数的时候执行了inner里面的内容,也同时调用爬虫函数本身 #就相当于调用了一个爬虫函数,没改变,调的还是爬虫函数,但实际上又增加了一个新的功能 #不仅执行了爬虫函数本身的功能还执行了inner功能 #这就是装饰器的作用 --- 问题1:为什么用爬虫函数接收timmer 解答: 我不能调用timmer,我只能调用爬虫函数,但又希望调用爬虫函数相当于调用了timmer,所以用爬虫函数接收timmer 问题2:装饰器里面执行一些动作的时候不知道放在func()上面还是下面 解答:有的地方是固定的,有的地方是不固定的,没有明确定义,根据需要来决定
import time def timmer(func): #func = 爬虫函数 def inner(): start =time.time() func() #爬虫函数的地址() ==>调用了爬虫函数 print(time.time()- start) #就是爬虫函数执行的时间 return inner @timmer #爬虫函数 = timmer(爬虫函数) #爬虫函数 = inner的地址 #@timmer自动把爬虫函数地址切换成inner地址 def 爬虫函数(): '''爬虫的功能''' 爬虫函数() #inner() 爬虫函数() #不管调用了多少次爬虫函数都相当于调inner() 爬虫函数() #调了多少次爬虫函数就调了多少次inner()
import time def timmer(func): #func = 爬虫函数 def inner(): start =time.time() func() #被装饰的函数 print(time.time()- start) #就是爬虫函数执行的时间 return inner @timmer #爬虫函数 = timmer(爬虫函数) #爬虫函数 = inner的地址 def 爬虫函数(): '''爬虫的功能''' #完成爬虫函数的基础上再完成一些新的功能 爬虫函数() #inner() # timmer 装饰器 # 爬虫函数 是被装饰的函数 # 调用 爬虫函数() 相当于调用inner函数 # inner函数里的func是通过timmer传递过来的爬虫函数 (inner里执行了被装饰的函数)
-
装饰的是谁inner中func()执行的就是谁
import time def timmer(func): #func = 计算器函数 def inner(): start =time.time() func() #被装饰的函数,计算器函数 print(time.time()- start) #就是爬虫函数执行的时间 return inner @timmer #爬虫函数 = timmer(爬虫函数) #爬虫函数 = inner的地址 def 爬虫函数(): '''爬虫的功能''' @timmer #计算器函数 = timmer(计算器) #计算器 = inner的地址 def 计算器(): '''计算器的功能''' 爬虫函数() #inner() #装饰的是谁inner中func()执行的就是谁
-
固定模式
def wrapper(func): def inner(*args,**kwargs): ret = func(*args,**kwargs) #func()就是wahaha函数 return ret return inner @wrapper #@wrapper ==> wahaha = wrapper(wahaha) = inner def wahaha(name): print(1234,name) return 123 @wrapper def qqxing(age): print(1234,age) return 456 ret = wahaha('alex') #wahaha就是装饰器的inner函数 print(ret) ret1 = xixi= qqxing('xiaxia') print(ret1)
-
想在调用wahaha之前做登录
def wrapper(func): def inner(*args,**kwargs): #在执行func之前写登录逻辑,登录成功才能执行wahaha ret = func(*args,**kwargs) #func()就是wahaha函数,wahaha是被装饰的函数,你希望被装饰的函数和你即将要添加的逻辑什么关系,你就在哪儿添加代码 #如果想在登录之后打印log执行func()之后执行打印log代码 return ret return inner @wrapper #@wrapper ==> wahaha = wrapper(wahaha) = inner def wahaha(name): print(1234,name) return 123 @wrapper def qqxing(age): print(1234,age) return 456 ret = wahaha('alex') #wahaha就是装饰器的inner函数 print(ret) ret1 = xixi= qqxing('xiaxia') print(ret1)
-
所有的独立函数都要使用的功能就写在装饰器里
-
问题装饰器里func之前要执行的功能,写单独的函数比较好,还是写功能比较好
-
答:如果功能需要的代码很长就写函数,如果很短就写功能代码
-
题目:编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件,只支持单用户的账号密码,给用户三次机会),要求登录成功一次,后续的函数都无需再输入用户名和密码
# 解析1:upload()、download()、move()这三个函数都需要先执行登录操作 # 解析2:登录成功后upload()、download()、move()这三个函数调用就没有顺序规定了 login_flag = False #先创建一个变量表示用户未登录状态 def login(func): def inner(*args,**kwargs): global login_flag if login_flag is False: #如果login_flag是False说明用户还没登陆过 username = input('username:') password = input('password:') with open(r'test',encoding='utf-8') as f: for line in f: line = line.strip() lst = line.split('|') user = lst[0] pwd = lst[1] if user == username and pwd == password: print('登陆成功') login_flag = True break else: print('登陆失败') if login_flag: #如果login_flag为True就执行以下代码 ret = func(*args,**kwargs) return ret return inner def upload(): print('') def download(): print('') def move(): print('') upload()
login_flag = False #先创建一个变量表示用户未登录状态 def auth(): global login_flag username = input('username:') password = input('password:') with open(r'G:\py27\其他脚本\test', encoding='utf-8') as f: for line in f: line = line.strip() lst = line.split('|') user = lst[0] pwd = lst[1] if user == username and pwd == password: print('登陆成功') login_flag = True break else: print('登陆失败') def login(func): def inner(*args,**kwargs): i = 0 #利用i约束用户只能登陆3次 while login_flag is False and i<3:#如果login_flag是False说明用户还没登陆过 auth() #auth()是用户登录的逻辑 i+=1 if login_flag: #如果login_flag为True的时候才能执行被装饰的函数(就是以下代码) ret = func(*args,**kwargs) #被装饰的函数 upload download move return ret return inner @login def upload(): print('这是一个上传文件的函数') @login def download(): print('这是一个下载文件的函数') @login def move(): print('这是一个移动文件的函数') upload()
生成器讲解
-
示例
def func(n): l = [] for i in range(n): egg = '鸡蛋%s'%i l.append(egg) return l ret = func(100) print(ret) 生成器:更省内存 def 老母鸡(n): #生成器函数 for i in range(n): egg = '鸡蛋%s'%i yield egg 生蛋器 = 老母鸡(20) #生成器 print(生蛋器) for egg in 生蛋器: print(egg)