闭包函数、装饰器、练习
今日内容详情
闭包函数
闭包函数简介
1.构成闭包函数的特征:
1.1 是定义在函数内部的函数
1.2 并且内部使用了外部函数名称空间的名字
只有符合上述两个特征的函数才能够称之为闭包函数
2.实例
def func1():
name = 'nana'
def func2():
print(name) # nana
return func2
res = func1()
res()
def func1(name):
# name = 'nana'
def func2():
print(name) # xiao
return func2
res1 = func1('xiao')
res1()
闭包函数的实际应用
给函数体代码传值的方式有两个,一是通过形参传值,而是通过闭包函数传值
1.通过形参传值
eg:
def func(name):
print(name) # nana
func('nana')
2.通过闭包函数传值
eg:
def func1(name):
def func2():
print(name) # nana
return func2
res = func1('nana')
res()
装饰器
装饰器简介
1.装饰器的本质:在不改变被装饰对象原来的'调用方式'和'内部代码'的情况下给被装饰对象添加新的功能
2.装饰器的原则:对修改封闭,对扩展开放
3.知识储备:
3.1 时间戳(秒数):指当前距离1970年1月1日0时0分0秒所经历的秒数
import time
print(time.time()) # 1657004718.7669668
装饰器前期推导
import time
def index():
time.sleep(3)
print('from index')
# 需求:统计函数index运行的时间
1.
start_time = time.time()
index() # from index
end_time = time.time()
print("该函数运行的时间是:",end_time-start_time) # 该函数运行的时间是: 3.010453462600708
ps:缺陷:如果有多个index需要统计执行时间,这需要 重复编写代码
解决措施:封装成函数
2.封装成函数
def func():
start_time = time.time() # 在调用index函数之前获取一下时间戳
index() # from index 调用index函数
end_time = time.time()
print("该函数运行的时间是:",end_time-start_time) # 该函数运行的时间是: 3.0146448612213135
func()
ps:缺陷:被调用的函数固定死了,如果有多个不同的函数想要统计执行时间,那么上述的解决措施不够完善
解决措施:给函数添加形参
3.给函数添加形参(方式一)
def func(xxx):
start_time = time.time()
xxx()
end_time = time.time()
print("该函数运行的时间是:",end_time-start_time)
def home():
time.sleep(5)
print('from home')
func(index) # from index 该函数运行的时间是: 3.0043678283691406
func(home) # from home 该函数运行的时间是: 5.01212739944458
ps:缺陷:当被调用的函数有形参时,上述代码报错
解决措施:用可变长参数解决
4.可变长参数解决
def func(xxx):
start_time = time.time()
xxx(*args,**kwargs) # 解释器识别不了 报错
end_time = time.time()
print("该函数运行的时间是:",end_time-start_time)
def home(a):
time.sleep(5)
print('from home')
func(index)
func(home)
ps:缺陷: 1.*args和**args在目前代码中无法实现
2.改变了原来的调用方式
解决措施:装饰器推导流程
5. 直接利用形参的形式传参无法实现不改变调用方式,第二种方式尝试用闭包函数
def outer(xxx):
def func():
start_time = time.time()
xxx()
end_time = time.time()
print("该函数运行的时间是:",end_time-start_time)
return func
def home():
time.sleep(5)
print('from home')
res = outer(index)
res() # from index 该函数运行的时间是: 3.0006649494171143
print(res) # <function outer.<locals>.func at 0x00000241241BD158>
res1 = outer(home)
res1() # from home 该函数运行的时间是: 5.002208709716797
print(res1) # <function outer.<locals>.func at 0x00000241241BD268>
# res和res1的名字是变量名,可以取任意的值,那我们用与被调用的函数的函数名,是否可以呢?
index = outer(index) # from index 该函数运行的时间是: 3.0072708129882812
index()
print(index) # <function outer.<locals>.func at 0x00000248DD6FD158>
home = outer(home) # from home 该函数运行的时间是: 5.007205009460449
home()
print(home) # <function outer.<locals>.func at 0x00000248DD6FD268>
ps:缺陷:当被调用的函数有形参时,上述代码报错
解决措施:用可变长参数解决
装饰 器优化版本
5.用可变长参数解决被张氏对象含参问题
import time
def index():
time.sleep(3)
print('from index')
return '执行index返回值'
def home(a):
time.sleep(5)
print('from home')
return '执行home返回值'
def outer(xxx):
def func(*args,**kwargs): # 此时可变长参数起得的在形参的作用
start_time = time.time()
xxx(*args,**kwargs) # 此时的可变长参数起的是在实参中的作用
end_time = time.time()
print("该函数运行的时间是:",end_time-start_time)
return func
index = outer(index) # from index
index() # 该函数运行的时间是: 3.0008184909820557
res1 = index()
print(res1) # None
home = outer(home)
home(1) # from home 该函数运行的时间是: 5.003419876098633
res2 = home(1)
print(res2) # None
ps:缺陷:当被想要获取被装饰对象的返回值时,获取不到
解决方法:在装饰器内增加一个返回值
6.获取被装饰对象的返回值
import time
def index():
time.sleep(3)
print('from index')
return '执行index返回值'
def home(a):
time.sleep(5)
print('from home')
return '执行home返回值'
def outer(xxx):
def func(*args,**kwargs): # 此时可变长参数起得的在形参的作用
start_time = time.time()
res = xxx(*args,**kwargs) # 此时的可变长参数起的是在实参中的作用
end_time = time.time()
print("该函数运行的时间是:",end_time-start_time)
return res
return func
index = outer(index) # from index
index() # 该函数运行的时间是: 3.0008184909820557
res1 = index()
print(res1) # 执行index返回值
home = outer(home)
home(1) # from home 该函数运行的时间是: 5.003419876098633
res2 = home(1)
print(res2) # 执行home返回值
装饰器固定模板
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
装饰器语法糖
语法糖加载被装饰对象函数上面
eg:
import time
from functools import wraps
def outer(func_name):
@wraps(func_name)
def func(*args,**kwargs): # 此时可变长参数起得的在形参的作用
start_time = time.time()
res = func_name(*args,**kwargs) # 此时的可变长参数起的是在实参中的作用
end_time = time.time()
print("该函数运行的时间是:",end_time-start_time)
return res
return func
@outer # index = outer(index)
def index():
time.sleep(3)
print('from index')
return '执行index返回值'
@outer # home = outer(home)
def home(a):
time.sleep(5)
print('from home')
return '执行home返回值'
index() # from index 该函数运行的时间是: 3.002319812774658
help(index) # Help on function index in module __main__: index()
home(1) # from home 该函数运行的时间是: 5.011131525039673
help(home) # Help on function home in module __main__: home(a)
作业
1.编写一个用户认证装饰器
基本要求
执行每个函数的时候必须先校验身份 eg: jason 123
from functools import wraps
def outer(func_name):
@wraps(func_name)
def inner(*args,**kwargs):
if tag_login is True:
res = func_name(*args,**kwargs)
else:
print("没弄上")
return res
return inner
dic_info = {}
def register():
user_name = input("请输入你的用户名>>>:").strip()
user_pwd = input("请输入你的用户名密码>>>").strip()
user_money = 100
dic_info['name'] = user_name
dic_info['pwd'] = user_pwd
dic_info['money'] = user_money
print(f'用户{user_name}注册成功')
def login():
user_name = input("请输入你的用户名>>>:").strip()
user_pwd = input("请输入你的用户名密码>>>").strip()
if user_name == dic_info['name'] and user_pwd == dic_info['pwd']:
print("登录成功")
global tag_login
tag_login = True
else:
print("用户名或密码错误")
@outer
def transfer():
user_trans_money = input("请输入你想要转账的金额>>>:").strip()
user_trans_money = int(user_trans_money)
if dic_info['money'] < user_trans_money:
print('钱不够')
else:
dic_info['money'] -= user_trans_money
print("转账成功")
@outer
def withdraw():
user_out_money = input("请输入你提款的金额:>>>").strip()
user_out_money = int(user_out_money)
if dic_info['money'] < user_out_money:
print('钱不够')
else:
dic_info['money'] -= user_out_money
print("提款成功")
dict1 = {
'1':register,
'2':login,
'3':transfer,
'4':withdraw
}
tag_login = False
while True:
print("""
======================
1.注册功能
2.登录功能
3.转账功能
4.提现功能
======================
""")
choice = input("请输入你的选择>>.:").strip()
if choice in dict1:
dict1.get(choice)()
else:
print("请输入正确的指令")
2.拔高练习(有点难度)
执行被装饰的函数 只要有一次认证成功 那么后续的校验都通过
函数:register login transfer withdraw
提示:全局变量 记录当前用户是否认证
from functools import wraps
def outer(func_name):
@wraps(func_name)
def inner(*args, **kwargs):
if tag_login is True:
res = func_name()
return res
else:
print("没弄上")
return inner
dic_outer = {}
def register():
user_id = input("请输入的你的用户名编号>>>:").strip()
if user_id in dic_outer:
print("该用户名已经存在了")
else:
user_name = input("请输入你的用户名>>>:").strip()
user_pwd = input("请输入你的用户名密码>>>").strip()
user_money = 100
dic_info = {}
dic_info['name'] = user_name
dic_info['pwd'] = user_pwd
dic_info['money'] = user_money
print(f'用户{user_name}注册成功')
dic_outer[user_id] = dic_info
def login():
user_id = input("请输入的你的用户名编号>>>:").strip()
if user_id not in dic_outer:
print("该用户不存在")
else:
user_name = input("请输入你的用户名>>>:").strip()
user_pwd = input("请输入你的用户名密码>>>").strip()
if user_name == dic_outer[user_id]['name'] and user_pwd == dic_outer[user_id]['pwd']:
print("登录成功")
global tag_login
tag_login = True
else:
print("用户名或密码错误")
@outer
def transfer():
user_id = input("请输入的你的用户名编号>>>:").strip()
if user_id not in dic_outer:
print("该用户不存在")
else:
user_trans_id = input("请输入你想转账的用户名编号>>>:").strip()
if user_trans_id not in dic_outer:
print("你想转的用户名不在")
else:
user_trans_money = input("请输入你想要转账的金额>>>:").strip()
user_trans_money = int(user_trans_money)
if dic_outer[user_id]['money'] < user_trans_money:
print('钱不够')
else:
dic_outer[user_id]['money'] -= user_trans_money
dic_outer[user_trans_id]['money'] += user_trans_money
print("转账成功")
@outer
def withdraw():
user_id = input("请输入的你的用户名编号>>>:").strip()
if user_id not in dic_outer:
print("该用户名不存在")
else:
user_out_money = input("请输入你提款的金额:>>>").strip()
user_out_money = int(user_out_money)
if dic_outer[user_id]['money'] < user_out_money:
print('钱不够')
else:
dic_outer[user_id]['money'] -= user_out_money
print("提款成功")
dict1 = {
'1': register,
'2': login,
'3': transfer,
'4': withdraw
}
tag_login = False
while True:
print("""
======================
1.注册功能
2.登录功能
3.转账功能
4.提现功能
======================
""")
choice = input("请输入你的选择>>.:").strip()
if choice in dict1:
dict1.get(choice)()
else:
print("请输入正确的指令")