什么是闭包函数
闭:指的是闭包函数数定义在一个函数内部的函数
包:该内部函数包含对外城函数作用域名字的引用
需要结合函数对象的概念将闭包函数返回到全局作用域去使用,从而打破函数层级的限制
为什么要用闭包函数
闭包函数提供了一种为函数体传值的解决方案
如何用闭包函数
# 为函数体传值的方式一:参数# def func(x,y):# print(x+y)## func(1,2) 3# 为函数体传值的方式二:闭包def outter(x,y): # x=1 # y=2 def func(): print(x+y) return funcf=outter(1,2) f() 3f() 3f() 3 解决方案一:参数# def get(url):# response=requests.get(url)# if response.status_code == 200:# print(len(response.text))# get('https://www.baidu.com')# get('https://www.baidu.com')# get('https://www.baidu.com')# get('https://www.tmall.com')# get('https://www.tmall.com')# url1='https://www.baidu.com'# url2='https://www.tmall.com'## get(url1)# get(url1)# get(url1)## get(url2)# get(url2)# get(url2) 解决方案二:闭包# def outter(url):# # url='https://www.baidu.com'# def get():# response=requests.get(url)# if response.status_code == 200:# print(len(response.text))# return get## baidu=outter('https://www.baidu.com')# baidu()# baidu()# baidu()## tmall=outter('https://www.tmall.com')# tmall()# tmall()# tmall()
装饰器
器:指的是具备某一功能的工具
装饰:值的是为了被装饰器对象添加新的功能
装饰器就是用来为了被装饰对象添加新功能的工具
注意: 装饰器本身可以是任意可调用对象,被装饰器的对象也可以是任意可调用对象
为什么用装饰器
开放封闭原则:封闭值的是对修改源代码封闭,对扩展功能开放
装饰器的实现必须遵循量大原则:
1 不修改被装饰对象的源代码
2不修改被装饰对象的调用方式
装饰器的目标:就是在遵循1和2原则的前提下为被装饰对象添加上新功能
import timedef index(): print('welcome to index page') time.sleep(3)def outter(func): # func=最原始那个index的内存地址 def wrapper(): start=time.time() func() #最原始的那个index的内存地址() stop=time.time() print('run time is %s' %(stop - start)) return wrapperindex=outter(index) #index=outter(最原始那个index的内存地址) #index=wrapper的内存地址index() #wrapper的内存地址()
装饰器的语法糖:在被装饰器对象正上方单独一行写@装饰器的名字
python解释器一旦运行到@装饰器的名字,就会调用装饰器然后将被装饰函数的内存地址当做参数传递给装饰器,最终将装饰器调用的结果赋值给原函数名 (原函数名=@外层函数运行结果返回值(二层函数名:就是加新功能的新函数名))
面试——解释@语法的时候自下而上运行
而执行装饰器的时候自上而下
# def o1(func): # def inner(*args, **kwargs): # print('o1 ------------') # 1 # result = func(*args, **kwargs) # print('o1 ============') # 5 # return result # return inner # # def o2(func): # def inner(*args, **kwargs): # print('o2 ------------') # 2 # result = func(*args, **kwargs) # print('o2 ============') # 4 # return result # return inner # @o1 # @o2 # def fn2(): # print('fn2 ============') # 3 # fn2() # 函数调用位置 # # 执行流程:函数调用位置 => o1装饰器inner => o2装饰器inner => 本体fn2 # # => 回到o2装饰器inner =>回到o1装饰器inner => 回到函数调用位置
import time## def timmer(func): #func=最原始那个home函数的内地址# def wrapper(*args,**kwargs): #args=('egon',) kwargs={}# start=time.time()# res=func(*args,**kwargs) #最原始那个home函数的内地址('egon')# stop=time.time()# print('run time is %s' %(stop - start))# return res# return wrapper## @timmer #index=timmer(index)# def index():# print('welcome to index page')# time.sleep(3)
import time def timmer(func): #func=wrapper2 def wrapper1(*args,**kwargs): start=time.time() res=func(*args,**kwargs) #res=wrapper2(*args,**kwargs) stop=time.time() print('run time is %s' %(stop - start)) return res return wrapper1 def auth(func): #func=最原始的那个index的内存地址 def wrapper2(*args,**kwargs): inp_user = input('please input your username: ').strip() inp_pwd = input('please input your password: ').strip() if inp_user == 'egon' and inp_pwd == '123': print('login successfull') res=func(*args,**kwargs) # 调用最原始的那个/也就是被装饰的那个函数 return res else: print('username or password error') return wrapper2 # 解释@语法的时候是自下而上运行 # 而执行装饰器内的那个wrapper函数时的是自上而下 @timmer # index=timmer(wrapper2) #index=wrapper1 @auth # index=auth(最原始的那个index的内存地址) #index=wrapper2 def index(): print('welcome to index page') time.sleep(3) index() #wrapper1()
装饰器模板
import time def outer(func): def wrapper(*args,**kwargs): #在调用函数前增加新功能 res=func(*args,**kwargs) #调用被装饰的 也就是最原始的那个函数 #在调用函数后加功能 return res return wrapper @outter #index=outer(index) #index =wrapper def index(): print ('welcome to index page') time.sleep(3) index() ef wrap(fn): def inner(*args,**kwargs): print('前面增功能') result=fn(*args,**kwargs) print('后面增功能') return result return inner@wrapdef fn1(): print('fn1的原功能')@wrapdef fn2(a,b): print('fn2的原有功能')@wrapdef fn3(): print('fn3的原有功能') return True@wrapdef fn4(a,*,x): print('fn4原有功能') return Truefn1()fn2(10,29)fn1()fn4(19,x=7)
def wrap(func): # 原版fn4 def inner(*args, **kwargs): # 新版fn4 pass # 新功能 if args[0] == 10: print('传入的a值是10') else: print('传入的a值不是10') result = func(*args, **kwargs) # 原功能 pass # 新功能 return result return inner @wrap # fn4 = wrap(fn4) def fn4(a, b, c, *, x, y, z): # 本尊 pass # fn4 = wrap(fn4) # 新版fn4(升级版fn4) fn4(1, 2, 3, x=10, y=20, z=30)
认证功能的装饰器import timedef auth(func): def wrapper(*args,**kwargs): inp_user = input('please input your username: ').strip() inp_pwd = input('please input your password: ').strip() if inp_user == 'egon' and inp_pwd == '123': print('login successfull') res=func(*args,**kwargs) # 调用最原始的那个/也就是被装饰的那个函数 return res else: print('username or password error') return wrapper@auth # index=auth(index) #index=wrapperdef index(): print('welcome to index page') time.sleep(3)index() #wrapper()
is_login = False # 登录状态 def login(): usr = input('usr: ') if not (len(usr) >= 3 and usr.isalpha()): print('账号验证失败') return False pwd = input('pwd: ') if usr == 'abc' and pwd =='123qwe': print('登录成功') is_login = True else: print('登录失败') is_login = False # 完成一个登录状态校验的装饰器 def check_login(fn): def inner(*args, **kwargs): # 查看个人主页或销售功能前:如果没有登录先登录,反之可以进入其功能 if is_login != True: print('你未登录') login() # 查看个人主页或销售 result = fn(*args, **kwargs) return result return inner # 查看个人主页功能 @check_login def home(): print('个人主页') # 销售功能 @check_login def sell(): print('可以销售') home()
带参装饰器 函数嵌套3层
def wrap(var): def outer(func): # outer的参数是固定的,就是被装饰的函数对象 print(var) def inner(*args, **kwargs): print(111111111111111) func(*args, **kwargs) print(333333333333333) return inner return outer# 1.调用wrap返回outer# 2.调用outer传入fn3返回inner给fn3@wrap(000) # wrap(000) => outer => @outer =>fn3 = outer(fn3)def fn3(): print(222222222222222)# 3.调用fn3就是调用inner,在inner内部调用原fn3fn3() 有参装饰器的参数写在语法糖()中
@wraps装饰器应该加到装饰器最内层的函数上 是为了函数的注释说明
def deco(func): @wraps(func) def wrapper(*args, **kwargs): res = func(*args, **kwargs) return res # wrapper.__name__=func.__name__ # wrapper.__doc__=func.__doc__ return wrapper@deco #index=deco(index) #index=wrapper函数的内存地址def index(): """ index 功能 """ print('welcome to index page') time.sleep(3)