闭包函数与装饰器
一:闭包函数
【1】
定义:
(1)内部函数被外部函数包裹住
(2) 内部函数包含对外部函数作用域名字的引用
【2】外部函数传参
方法一:直接传参
例如:
def index(args): print('位置传参') index(args='传参') # 位置传参
方法二:闭包传参
def outter(): def inner(): x = 1 print('from inner' ,x) return inner res = outter() # 获取的是inner的内存地址 因为内部地址返回值是inner 将内部地址赋值给一个变量 res() # from inner 因为res此时获取的是inner的内存地址 通过该地址可以调用内部函数
PS:
(1)闭包函数 打破了层级关系的限制 可以在任意位置调用
(2)函数作用域在固定阶段就已经固定死了 与其调用位置无关
例如:
def outter(): x = 2 # 次优先调用 def inner(): x = 1 # 优先调用 print('from inner' ,x) return inner res = outter() x = 111 # 最后调用 res() # 因为其调用的是inner这个函数
基本定义模块:
def outter(x): def inner(): print('你要执行的操作') return inner # 返回内部函数的内存地址 res = outter('参数值') # 接收内部函数地址 并向外部函数传参 res() # 调用内部函数
二:装饰器
【1】
无参装饰器:
开放封闭原则:
(1)开放:在原有的软件功能进行扩展 开发新的功能
(2)封闭:不能修改源代码 以及源代码的调用方式
(1)无参装饰器的基础
装饰器:在不修改被装饰器源代码以及调用方式的基础上 添加新的功能
例如:
import time def index(): time.sleep(1) print('index原函数') return 'index_SR' # 方法一:创建新函数 直接传参法 def inner(func): start_time = time.time() func() # 写变量的方法可以同时允许多个函数调用 end_time = time.time() print('相差时间%s'%(end_time-start_time)) inner(index) # 相差时间1.0 # PS:虽然添加新功能且没有修改源代码 但是调用方式发生改变 # 方法二:创建新函数 闭包传参 def outer(func): def inner(): start_time = time.time() func() end_time = time.time() print('相差时间%s'%(end_time-start_time)) return inner index = outer(index) # 获取inner的内存地址 并赋值给和原函数名一样的变量 index() # 通过获取的内存地址 调用内部的函数
(2)无参装饰器升级版:
简易版问题一:不能获取原始函数的返回值
例如:
def index(): time.sleep(1) print('index原函数') return 'index_SR' def outer(func): def inner(): start_time = time.time() func() end_time = time.time() print('相差时间%s'%(end_time-start_time)) return return inner index = outer(index) res = index() print(res) # None 因为我此时调用的是inner内部函数 内部函数无返回值
解决办法:
def index(): time.sleep(1) print('index原函数') return 'index_SR' def outer(func): def inner(): start_time = time.time() res = func() #调用的是最原始的函数 end_time = time.time() print('相差时间%s'%(end_time-start_time)) return res # 返回原始函数的返回值 return inner index = outer(index) res = index() print(res) # index_SR 此时inner内部有返回原始函数的返回值
简易版问题二:是否携带形参
例如:
def index(): time.sleep(1) print('index原函数') return 'index_SR' def home(name): time.sleep(1) print('home原函数') return 'home_SR' def outer(func): def inner(*args,**kwargs): start_time = time.time() res = func(*args,**kwargs) #调用的是最原始的函数 end_time = time.time() print('相差时间%s'%(end_time-start_time)) return res # 返回原始函数的返回值 return inner index = outer(index) index() home = outer(home) home('SR') ''' 问题现象: (1) 函数home会报错:TypeError: inner() takes 0 positional arguments but 1 was given 因为home调用的是内部函数inner 但是此时inner属于无参函数 home传参导致报错 (2) 如果将inner内部传参 但是index属于无参函数 如果传参导致index不能正确调用 解决办法:在内部函数在允许任意函数调用 *args,**kwargs '''
(3) 无参函数的表达式:
def outer(func): def warpper(*args,**kwargs): print('你要执行的动作') res = func(*args,**kwargs) # 原函数的返回值赋值给变量 允许所有函数调用 return res # 返回原函数返回值 return warpper # 将内部函数的内存地址返回 name = outer('原函数') # 内部函数的内存地址 name等于原函数的函数名 name() # 调用内部函数
【2】
装饰器语法糖:
(1)产生背景:
(1)当我们想要调用装饰器的时候 需要将原函数名赋值给装饰器 并且将赋值后的函数名更改为与原函数一模一样
(2)大量的重复赋值更名动作比较繁琐
(2)解决办法:
(1)当采用语法糖的时候 语法糖会自动将与自己紧挨的函数当做变量赋值给装饰器
(2)并且将赋值后的名称更改为与原函数一模一样
例如:
def outer(func): def inner(*args,**kwargs): start_time = time.time() res = func(*args,**kwargs) end_time = time.time() print('延迟时间%s'%(end_time-start_time)) return res return inner @outer # index = outer(index) def index(): time.sleep(1) print('index原函数') return 'index_SR' @outer # index = outer(home) def home(name): time.sleep(1) print('home原函数') return 'home_SR'
例题:用户登录验证
current_user = {'usernmae':None} # 存放登录的用户 def auth_login(func): def inner(*args,**kwargs): if current_user['usernmae']: # 如果已经登录 不用再次登录 res = func(*args, **kwargs) return res username = input('请输入用户名>>:').strip() password = int(input('请输入密码>>:'.strip())) if username == 'SR' and password == 123: print('登录成功') current_user['usernmae'] = username res = func(*args,**kwargs) return res else: print('登录失败') return inner @auth_login def index(): time.sleep(1) print('index原函数') return 'index_SR' @auth_login def home(name): time.sleep(1) print('home原函数') return 'home_SR' index() home('SR')
【3】有参装饰器
import time current_user = {'usernmae':None} def timer(func): def inner(*args,**kwargs): start_time = time.time() res = func(*args,**kwargs) end_time = time.time() print('延迟时间%s'%(end_time-start_time)) return res return inner def auth_login2(source): def auth_login(func): def wrapper(*args,**kwargs): if current_user['usernmae']: res = func(*args, **kwargs) return res else: username = input('请输入用户名>>:').strip() pwd = int(input('请输入密码>>:'.strip())) if source == 'file': if username == 'SR' and pwd == 123 : current_user['usernmae'] =True print('登录成功') res = func(*args,**kwargs) return res else: print('登录失败') else: print('MySql') return wrapper return auth_login @auth_login2('file') # 调用装饰器最外部函数 @timer def index(): time.sleep(1) print('form index') return 'index_SR' index()
【4】装饰器修复技术
作用:
(1)返回原函数真正的内存地址
(2)返回原函数的注释等
例如
import time from functools import wraps current_user = {'usernmae':None} def timer(func): @wraps(func) def inner(*args,**kwargs): start_time = time.time() res = func(*args,**kwargs) end_time = time.time() print('延迟时间%s'%(end_time-start_time)) return res return inner def auth_login2(source): def auth_login(func): def wrapper(*args,**kwargs): if current_user['usernmae']: res = func(*args, **kwargs) return res else: username = input('请输入用户名>>:').strip() pwd = int(input('请输入密码>>:'.strip())) if source == 'file': if username == 'SR' and pwd == 123 : current_user['usernmae'] =True print('登录成功') res = func(*args,**kwargs) return res else: print('登录失败') else: print('MySql') return wrapper return auth_login @auth_login2('file') # 调用装饰器最外部函数 @timer def index(): time.sleep(1) print('form index') return 'index_SR' index()