7.11函数(二)
作者:互联网
一、闭包函数
1.什么是闭包函数:
(1)闭:定义在函数内部的函数
(2)包:内部函数引用了外部函数作用域的名字
2.给函数传值的两种方式
(1)传参
def index(name): print(name) index('francis') # 传参
(2)闭包
def outter(x,y): # x = 1 通过传参获得 # y = 40 通过传参获得 def my_max(): if x > y: return x return y return my_max res = outter(1,40) # res就是my_max函数的内存地址 print(res()) # 调用函数my_max,会去函数outter中取参数,这就是内部函数引用了外部函数作用域的名字
二、装饰器
1.什么是装饰器:
装饰:给被装饰对象添加新的功能
器:就是一个工具
2.为什么要用装饰器
(1)装饰器遵循开放封闭的原则
开放:对扩展开放(能对原来的函数添加功能)
封闭:对修改封闭(不能修改原来的函数功能)
(2)装饰器(是可调用对象)必须遵循的两个原则
1.不改变被装饰对象(原函数)的源代码
2.不改变被装饰对象(原函数)的调用方式
3.补充知识:
import time # 调用模块 print(time.time()) # 打印时间戳,打印的是当前时间距离1970-1-1 00:00:00相差的秒数(1970-1-1 00:00:00是Unix诞生元年) time.sleep(3) # 让cpu睡三秒,传参数,表示让你的程序暂停几秒 print('程序停了3秒')
三、装饰器简单版本
1.用函数实现让程序停3秒,再执行打印功能
import time def index(): time.sleep(3) print('程序停了3秒') index()
2.如何实现:
统计执行index函数(上面的)共用了几秒,且不改变原函数的调用方式和源代码。
import time def index(): time.sleep(3) print('程序停了3秒') def outter(func): # func = index 就是最原始的index函数的内存地址 def get_time(): start = time.time() # 统计时间戳 func() # func = index 加括号调用最原始的index函数(让程序停3秒的函数) end = time.time() # 统计时间戳 print('index运行了:%s'%(end-start)) # 两次统计时间戳,用了几秒 return get_time # 返回get_time函数的内存地址 index = outter(index) # outter(index)执行之后返回的是get_time函数的内存地址 # 所以第一个index指向get_time函数的内存地址,第二个index是最原始的index函数内存地址(让程序停3秒的函数) index() # 就相当于get_time函数加上括号调用了
四、装饰器升级版
1.如何实现:
用一个装饰器装饰两个函数,其中一个不用传参,一个需要传参,且该装饰器的返回值就是原函数的返回值,原函数:
import time def index(): time.sleep(3) print('程序停了3秒') return 'index的返回值' res = index() print(res) def login(name): time.sleep(1) print('%s是帅比'%name) return 'login的返回值' res1 = login('francis') print(res1)
2.实现:
import time def index(): time.sleep(3) print('程序停了3秒') return 'index的返回值' def login(name): time.sleep(1) print('%s是帅比'%name) return 'login的返回值' def outter(func): # func = 最原始的index或者login函数的内存地址 def get_time(*args, **kwargs): # *和**在形参中的用法,接收多余的位置参数和关键字参数 start = time.time() res = func(*args, **kwargs) # 最原始的index或者login函数的内存地址,加括号调用,并接收原函数的返回值 # *和**在实参中的用法,打散容器类型中的参数和字典中的参数 end = time.time() print('%s函数运行了:%s'%(func,end-start)) return res # 返回原函数的返回值 return get_time index = outter(index) # 第二个index是最原始的index函数的内存地址 res = index() print(res) # 原index函数的返回值 login = outter(login) # 第二个login是最原始的login函数的内存地址 res1 = login('francis') print(res1) # 原login函数的返回值View Code
实现了无参函数和有参函数都可以直接调用同一个装饰器(装饰器可以接收任意数量的参数)
五、装饰器语法糖
1.上述实现的装饰器中,如果想要装饰某个函数,需要代码比如:index = outter(index)、login = outter(login)来实现,很麻烦,这时候可以用到装饰器语法糖。
import time def outter(func): # func = 最原始的index或者login函数的内存地址 def get_time(*args, **kwargs): # *和**在形参中的用法,接收多余的位置参数和关键字参数 start = time.time() res = func(*args, **kwargs) # 最原始的index或者login函数的内存地址,加括号调用,并接收原函数的返回值 # *和**在实参中的用法,打散容器类型中的参数和字典中的参数 end = time.time() print('%s函数运行了:%s'%(func,end-start)) return res # 返回原函数的返回值 return get_time @outter # index = outter(index) def index(): time.sleep(3) print('程序停了3秒') return 'index的返回值' @outter # login = outter(login) def login(name): time.sleep(1) print('%s是帅比'%name) return 'login的返回值' res = index() print(res) # 原index函数的返回值 res1 = login('francis') print(res1) # 原login函数的返回值View Code
@outter会将紧挨着他的可调用对象当作他的参数传入直接执行,并接收返回值
2.书写规范:
语法糖在书写的时候应该与被装饰对象紧紧挨着,两者之间不要有空格
六、装饰器模板
def outter(func): def inner(*args,**kwargs): print('执行被装饰函数之前,你可以做的操作') res = func(*args,**kwargs) print('执行被装饰函数之后,你可以做的操作') return res return inner
1.如何实现一个认证装饰器:
执行函数index之前必须先输入用户名和密码,正确之后才能执行index,如果之后再执行函数login,则不需要再登录
import time user_dic = {'is_login':None} # 全局定义一个空字典,判断用户是否已登录过 def outter(func): def inner(*args,**kwargs): if user_dic['is_login']: # 判断是否已登录 res = func(*args, **kwargs) # 登陆过直接执行原函数 return res else: username = input('please input your username>>>:').strip() password = input('please input your password>>>:').strip() if username == 'francis' and password == '123': user_dic['is_login'] = True # 登陆成功后,修改字典为True res = func(*args,**kwargs) return res else: print('username or password error') return inner @outter # index=outter(index) def index(name): time.sleep(1) print('%s是帅比'%name) return 666 @outter # login=outter(login) def login(): time.sleep(1) print('from login') return 999 print(index('francis')) print(login())View Code
七、多层装饰器
1.给index函数套多个装饰器,使index函数先执行认证功能再统计函数运行时间
import time user_dic = {'is_login':None} # 全局定义一个空字典,判断用户是否已登录过 def outter(func): def inner(*args,**kwargs): if user_dic['is_login']: # 判断是否已登录 res = func(*args, **kwargs) # 登陆过直接执行原函数 return res else: username = input('please input your username>>>:').strip() password = input('please input your password>>>:').strip() if username == 'francis' and password == '123': user_dic['is_login'] = True # 登陆成功后,修改字典为True res = func(*args,**kwargs) return res else: print('username or password error') return inner def outter1(func): # func = 最原始的index或者login函数的内存地址 def get_time(*args, **kwargs): # *和**在形参中的用法,接收多余的位置参数和关键字参数 start = time.time() res = func(*args, **kwargs) # 最原始的index或者login函数的内存地址,加括号调用,并接收原函数的返回值 # *和**在实参中的用法,打散容器类型中的参数和字典中的参数 end = time.time() print('%s函数运行了:%s'%(func,end-start)) return res # 返回原函数的返回值 return get_time @outter # index=outter(get_time) index=inner函数的地址 @outter1 # get_time=outter1(index) index是最原始的index的内存地址 def index(): time.sleep(3) print('index') return 'from index' index()View Code
方法是在index函数上套两个装饰器语法糖
2.着重注意:
(1)装饰器在装饰函数的时候,执行顺序是是从下往上(紧贴函数到远离函数)
(2)装饰器在执行的时候,执行顺序是从上往下的(离被装饰的函数最远的装饰器最先执行,最后执行的是紧贴函数的装饰器)
八、装饰器修复技术
1.作用
(1)用户查看被 装饰了的函数 的函数名的时候,看到的就是 原函数 的内存地址
(2)用户查看被 装饰了的函数 的注释的时候,看到的就是 原函数 的注释
2.如何用
from functools import wraps def outter(func): @wraps(func) # 装饰器修复技术 def inner(*args,**kwargs): ''' 这是inner函数 :param args: :param kwargs: :return: ''' print('执行被装饰函数之前 你可以执行的操作') res = func(*args,**kwargs) print('执行被装饰函数之后 你可以执行的操作') return res return inner @outter # index = outter(最原始的index的内存地址) def index(): ''' 这是index函数 :return: ''' pass print(index) # 查看函数的内存地址 返回的就是原函数index的 print(help(index)) # 查看函数的注释 返回的就是原函数index的 print(index.__name__) # 查看函数名字符串形式 返回的就是indexView Code
(1)在装饰器外导入一个模块:from functools import wraps
(2)在装饰器里写入:@wraps(func),括号内的形参与装饰器内的一致
九、多层装饰器
1.习题:求index运行之后的打印结果
def outter1(func1): print('加载了outter1') def wrapper1(*args,**kwargs): print('执行了wrapper1') res1=func1(*args,**kwargs) return res1 return wrapper1 def outter2(func2): print('加载了outter2') def wrapper2(*args,**kwargs): print('执行了wrapper2') res2=func2(*args,**kwargs) return res2 return wrapper2 def outter3(func3): print('加载了outter3') def wrapper3(*args,**kwargs): print('执行了wrapper3') res3=func3(*args,**kwargs) return res3 return wrapper3 @outter1 # index = outter1(wapper2) @outter2 # wrapper2 = outter2(wrapper3) @outter3 # wrapper3 = outter3(index) 最原始的index的内存地址 def index(): print('from index') index()View Code
2.代码执行顺序:
标签:index,return,7.11,time,print,def,函数 来源: https://www.cnblogs.com/francis1/p/11178574.html