今日学习内容
闭包函数简介
闭包函数
-
定义在函数内部的函数
-
内部函数使用了外部函数名称空间里的名字
def func(): username = 'xz' #形参接收实参 def index(): print(username) return index func() # func('xz') 相当于 username = 'xz' res = func() print(res) #<function func.<locals>.index at 0x000001CF915F8A60> res() #注意:外面的func运行后不会立马关闭,因为func内部还有函数,当后面的函数整个运行结束才结束。
闭包函数的实际应用
函数体代码传值的方式有2种
-
形参
def func(xxx) print(xxx)
-
闭包函数
def index(): username = 'xz'
def func():
print(username)
return func
res = index()
res()# xz
def index(username):
def func():
print(username)
return func
res = index('xz')
res()
res1 = index('wyb')
res1()
作用:可以在任意位置调用函数然后反复使用,注意的是当index重新输入一个实参,就会是原来和username绑定的数据值就会断开,重新绑定新的数据值 wyb。
装饰器简介
-
装饰器的本质
在不改变被装饰对象原来的
调用方式
和内部代码
的情况下给被装饰对象的添加新的功能。
def func()
print(123)
func() #每次执行之前需要校验用户身份
-
装饰器的原则
不能修改代码,只能扩展代码。
-
知识储备
import time print(time.time()) #1657009750.2860615 '''时间戳(秒数):当前距离1970年1月1日0时0分0秒''' time.sleep(3) '''让程序原地等待三秒''' print('3秒后我出来了!!!')
装饰器前期推导
-
index前后加个
时间戳
,不影响调用方式
和内部代码
。import time def index(): time.sleep(2) print('from index') '''统计index函数的执行时间''' start_time = time.time() # 在调用index函数之前获取一下时间戳 index() # 调用index函数 end_time = time.time() print('函数的执行时间是:', end_time - start_time) '运行结果: from index 函数的执行时间是: 2.011164903640747' #这是没改变调用方式和内部代码,但是在面对多个index函数需要统计时间就很麻烦!!! """ 缺陷 如果有多个index需要统计时间 则需要重复编写代码 解决措施: 封装成函数 def get_time() """
-
多个同一个
函数需要统计时间,需要封装成函数
。'封装函数后' import time def index(): time.sleep(2) print('from index') def get_time(): start_time = time.time() # 在调用index函数之前获取一下时间戳 index() # 调用index函数 end_time = time.time() print('函数的执行时间是:', end_time - start_time) get_time() '运行结果: from index 函数的执行时间是: 2.0149083137512207' """ 缺陷 如果有多个不同的函数需要统计时间 那么上述的解决措施不够完善 解决措施: 给函数体添加形参(动态传参) """
-
多个不同
的函数需要统计时间,可以封装
后用形参(动态传参
)。import time def index(): time.sleep(2) print('from index') def home(): time.sleep(3) print('from home') def get_time(a): start_time = time.time() # 在调用index函数之前获取一下时间戳 a() # 调用index函数,如果我们需要执行多个不同的代码可以引出一个变量名来代替函数名,这里需要添加实参为函数名,形参为变量名,然后就是将变量名和index函数名绑定,也就是将index赋值给左边的变量名。 end_time = time.time() print('函数的执行时间是:', end_time - start_time) get_time(index) get_time(home) '运行结果: from index 函数的执行时间是: 2.0056252479553223 from home 函数的执行时间是: 3.0146279335021973' """ 缺陷 不同形参个数的函数无法兼容统计 解决措施: *args **kwargs 但是在我们目前的代码中无法实现(暂且忽略) """
-
不同形参函数的个数兼容统计(*args **kwargs)
def home(): time.sleep(5) print('from home') def get_time(xxx): start_time = time.time() # 在调用index函数之前获取一下时间戳 xxx() # 调用index函数 #xxx(*args, **kwargs)会报错,因为代码没法识别括号里的东西是什么。 end_time = time.time() print('函数的执行时间是:',end_time - start_time) # get_time(index) # get_time(home) """ 缺陷 改变了原来的调用方式 解决措施: 装饰器推导流程 """
装饰器各种版本
如果index或者home函数内有形参,则不能因形参的方式传值,而是用闭包函数来做。
def outer(xxx):
def get_time():
start_time = time.time()
xxx() #调用index函数
end_time = time.time()
print('函数的执行时间是:', end_time - start_time)
return get_time
res = outer(index) #
res()#get_time()
res1 = outer(home)
res1()
'运行结果:
from index
函数的执行时间是: 2.0112996101379395
from home
函数的执行时间是: 3.0021297931671143'
还是不符合装饰器的条件,不满足调用方式。
所以我们可以改变变量名。
def outer(xxx):
def get_time():
start_time = time.time()
xxx() #调用index函数
end_time = time.time()
print('函数的执行时间是:', end_time - start_time)
return get_time
index = outer(index) #
index()#get_time()
home = outer(home)
home()
import time
def index(name):
time.sleep(2)
print('from index')
def home():
time.sleep(3)
print('from home')
"""针对有参无参函数如何兼容"""
def outer(a):
def get_time(*args, **kwargs):
start_time = time.time() # 在调用index函数之前获取一下时间戳
res = a(*args, **kwargs) # 调用index函数
end_time = time.time()
print('函数的执行时间是:', end_time - start_time)
return res
return get_time
index = outer(index)
index('xz')
xxx = index #index为outer函数返回结果get_time.赋值给左边
print(xxx) #get_time 的内存地址
'运行结果:
from index
函数的执行时间是: 2.0117368698120117
<function outer.<locals>.get_time at 0x0000026EA19D8B80>'
装饰器的固定模板
from functools import wraps
def outer(func_name):
#@wraps(func_name) # 仅仅是为了让装饰器不容易被别人发现 做到真正的以假乱真
def inner(*args, **kwargs):
print('执行被装饰对象之前可以做的额外操作')
res = func_name(*args, **kwargs)
print('执行被装饰对象之后可以做的额外操作')
return res
return inner
inner = outer()
inner()
装饰器语法糖
# 装饰器语法糖
import time
#将紧挨着这个语法糖的函数名当做函数的参数赋值给变量名
@outer # home = outer(真正的函数名home)
def home():
'''我是home函数 我要热死了!!!'''
time.sleep(1)
print('from home')
return 'home返回值'
help
# help(home)
# print(home)
home()
def index():
'我是index函数 我的功能很强大'
pass
help(index)
#帮助我们知道括号内的函数内容是什么,有些需要该函数上加个from functools import wraps 函数内加个#@wraps(func_name) # 仅仅是为了让装饰器不容易被别人发现 做到真正的以假乱真
作业
1.编写一个用户认证装饰器
基本要求
执行每个函数的时候必须先校验身份 eg: jason 123
拔高练习(有点难度)
执行被装饰的函数 只要有一次认证成功 那么后续的校验都通过
函数:register login transfer withdraw
提示:全局变量 记录当前用户是否认证
def login():
print('登录成功!')
return
def outer(login_func):
def func(*args,**kwargs):
username = input('请输入用户名>>>:').strip()
password = input('请输入密码>>>:').strip()
if username == 'xz' and password == '123':
res = login_func(*args,**kwargs) #login函数的返回值
return res # func的函数返回值为res
else:
print('登录失败!')
return func
login= outer(login)
login()
原创文章,作者:carmelaweatherly,如若转载,请注明出处:https://blog.ytso.com/272996.html