装饰器
今日内容概要
- global与nonlocal
- 函数名的多种用法
- 闭包函数
- 装饰器简介
- 无参装饰器
global 与nonlocal
-
golobal 改变全局变量
-
nonlocal 改变外层局部名称空间的变量
函数名的多种用法
-
可以当成实参
# 可以当成实参传递 def index(xx): print(xx) def func():pass index(func) -
可以放到容器里面
def login(): print("登录") def register(): print("注册") def select(): print("查看") data_dict = { "1": login, "2": register, "3": select, "4": exit } while True: print(""" 1.登录 2.注册 3.查看 4.退出 """) choice = input("请输入编号:").strip() if not choice.isdigit(): print("请输入数字") continue if choice not in data_dict: print("编号不存在") data_dict.get(choice)() -
可以被赋值给别的变量名
def func(): print("哈哈") res = func res() -
可以当作返回值
def func(): print("哈哈") return func res = func() res()
闭包函数
内部函数可以引用外层函数的名字
闭包函数的应用就是
"""定义到内部的函数用到外部函数中的名字"""
def index():
name = "jason"
def func():
print(name)
"""闭包函数"""
装饰器简介
-
在不改变原函数体代码及调用方式的情况下,为原函数添加新的功能
-
条件
1.不改变原函数体代码
2.不改变原函数体的调用方式 -
结果
添加新的功能
-
-
本质
并不是一门新的技术 而是由函数参数、名称空间、函数名多种用法、闭包函数组合到一起的结果
-
口诀
对修改封闭 对扩展开放
解释:对修改内部代码和调用方式不行,我原有的你不能动, 但是你可以扩展我的功能
-
储备知识
# 时间操作 import time # print(time.time()) # 1665476504.078971 # 打印出来的是时间戳 是计算机元年到当前时间过去了多少秒 # 计算机元年 一九七零年一月一日零时零点零分 1970.01.01 00:00:00 # time.sleep(3) # print("哈哈哈") count = 0 start_time = time.time() while count < 10000: # print(1) count += 1 end_time = time.time() print("消耗时间", end_time - start_time)
装饰器推导流程
""""
在不改变原函数体代码及调用方式的情况下,为原函数添加新的功能
条件 1.不改变原函数体代码
2.不改变原函数体的调用方式
结果 添加新的功能
"""
import time
# 原函数
# def index():
# print("from index")
# index()
# 需求添加计时器功能 就是计算运行时间
# 因为函数定义阶段不能动 所以只能动调用阶段
# import time
# def index():
# print("from index")
#
# start = time.time()
# index()
# time.sleep(0.3)
# end = time.time()
# print(end - start)
# 虽然实现了 但是
# 每次调用都得重新写一遍
# 重新写一遍 重新写一变 代码的重用
# 1. 循环 2.函数 有这两种方式的实现 而我们需要在不同的位置重用代码
# 所以我们选择函数 把代码缩进 进去
# def index():
# print("from index")
#
# def inner():
# start = time.time()
# index()
# time.sleep(0.3)
# end = time.time()
# print(end - start)
# inner(index)
# 虽然实现了但是原函数写死了 现在只能统计index的执行时间了
# 不就原函数写死 我把他提上去 变成形参
# def index():
# print("from index")
#
# def inner(xxx):
# start = time.time()
# xxx()
# time.sleep(0.3)
# end = time.time()
# print(end - start)
# inner(index)
# 但是条件不符合 调用方式改变了
# 因为是在传参的时候遇到了问题所以 这种传参pass
# 但是我们学了两种传参方式既然这种不行那就换一种
# 闭包
# 闭包的定义 在内部函数引用外部函数的名字
# def index():
# print("from index")
#
# def outer(xxx):
# def inner():
# start = time.time()
# xxx()
# time.sleep(0.3)
# end = time.time()
# print(end - start)
# return inner
#
# index = outer(index)
# indexr()
index = outer(index)
outer(index) = inner


# 这只是如果原函数是无参函数的时候
# 当有参函数的时候怎么办
# 就可以用可变长形参和可变长实参来接收 和传递
# def index(aa, ):
# print("from index", aa)
#
#
# def outer(xxx):
# def inner(*args, **kwargs): # 他是怎么接的
# start = time.time()
# xxx(*args, **kwargs) # 我就是怎么传的
# time.sleep(0.3)
# end = time.time()
# print(end - start)
#
# return inner
#
#
# inner = outer(index)
# inner(aa=1)
# def aa(*args, **kwargs):
# # print(args, kwargs)
# print(*args, **kwargs) # [1, 2, 3] {'user': 'jason', 'pwd': 123}
# print 不了 **字典
#
# aa(x=1)
# print(x=1) 就会报错
# 形参 的 * 多余的位置参数以元组的形式接收给 * 后args
# 实参 的 * 就是for循环 一个个取出来 然后一次性的传给函数
# 形参 的 ** 会把多余的关键字参数 以键值对的形式 放在字典里
# 实参 的** 会把字典里的键值对写成 键=值的形式
# 需求当原函数有返回值的时候 怎么办
def index(aa, ):
print("from index", aa)
return "嘿嘿嘿"
def outer(xxx):
def inner(*args, **kwargs): # 他是怎么接的
start = time.time()
res =xxx(*args, **kwargs) # 我就是怎么传的
time.sleep(0.3)
end = time.time()
print(end - start)
return res
return inner
index = outer(index)
res = index(aa=1)
print(res)
# 只用那个值来接收原函数的返回值 然后在把它返回出来就行了
# 这样一个装饰器的就完成了 只是需要自己先写 inner = outer(index)


装饰器模板
def outer(func):
def inner(*args, **kwargs):
res = func(*args, **kwargs)
return res
return inner
装饰器语法糖
# 如果不想写那么 就需要语法糖
# 如果要想使用语法糖一定要把装饰器写到 被装饰函数的上面
# def outer(xxx):
# def inner(*args, **kwargs): # 他是怎么接的
# start = time.time()
# res =xxx(*args, **kwargs) # 我就是怎么传的
# time.sleep(0.3)
# end = time.time()
# print(end - start)
# return res
#
# return inner
#
#
# @ outer
# def index(aa, ):
# print("from index", aa)
# return "嘿嘿嘿"
#
#
# res = index(aa=1)
# print(res)
作业
1.整理今日内容及博客
2.尽量搞懂装饰器推导流程
3.编写一个用户认证装饰器
函数:register login transfer withdraw
基本要求
执行每个函数的时候必须先校验身份 eg: jason 123
拔高练习(有点难度)
执行被装饰的函数 只要有一次认证成功 那么后续的校验都通过
提示:全局变量 记录当前用户是否认证
# 3.编写一个用户认证装饰器
# 函数:register login transfer withdraw
# 基本要求
# 执行每个函数的时候必须先校验身份 eg: jason 123
# 拔高练习(有点难度)
# 执行被装饰的函数 只要有一次认证成功 那么后续的校验都通过
# 提示:全局变量 记录当前用户是否认证
import os
import json
path = os.path.dirname(__file__)
file_path = os.path.join(path, "db")
tag_dict = {"user": None}
def save(name, data):
"""保存"""
if not os.path.exists(file_path):
os.mkdir("db")
with open(r"{}/{}.json".format(file_path, name), "w", encoding="utf8") as f:
json.dump(data, f)
return
def select(name):
"""查看"""
if not os.path.exists(file_path):
os.mkdir("db")
name_list = os.listdir(file_path)
# 如果文件不存在(用户没有注册)
if "{}.json".format(name) not in name_list:
# 则返回空
return
# 文件存在 则打开文件
with open(r"{}/{}.json".format(file_path, name), "r", encoding="utf8") as f:
data = json.load(f)
return data
def outer(func):
def inner(*args, **kwargs):
if tag_dict["user"]:
res = func(*args, **kwargs)
return res
else:
print("您现在还没有权限, 请先登录")
login()
return inner
def register():
"""注册"""
while True:
data_dict = {}
data_dict["name"] = input("请输入用户名:").strip()
if data_dict["name"].lower() == "q":
break
res = select(data_dict["name"])
if res:
print("用户名已存在")
continue
data_dict["pwd"] = input("请输入密码:").strip()
data_dict["quota"] = 15000
save(data_dict["name"], data_dict)
print("[{}]注册成功".format(data_dict["name"]))
def login():
"""登录"""
while True:
name = input("请输入用户名:").strip()
if name.lower() == "q":
break
pwd = input("请输入人密码:").strip()
data = select(name)
if not data:
print("用户不存在, 请先注册")
continue
if data["name"] == name and data["pwd"] == pwd:
print("登陆成功!")
tag_dict["user"] = name
break
else:
print("用户名或密码错误")
@outer
def select_data():
name = tag_dict["user"]
data = select(name)
if not data:
print("用户不存在")
return
print(data)
@outer
def transfer():
"""转账"""
while True:
name = tag_dict["user"]
t_name = input("请输入转账对象:").strip()
if t_name.lower() == "q":
break
res = select(t_name)
if not res:
print("转账用户不存在!")
continue
# 获取想要转账的金额
money = input("请输入转账金额:").strip()
# 获取转账用户的数据
data = select(name)
# 获取转账用户的额度
name_quota = data["quota"]
# 转账用户的额度 减去 所转的金额
new_money = name_quota - int(money)
data["quota"] = new_money
# 保存 用户的数据
save(name, data)
# 获取 被转账用户的数据
t_data = select(t_name)
# 获取 被转帐用户的金额
t_quota = t_data["quota"]
# 被转帐用户的金额加上转账金额
new_t_money = t_quota + int(money)
t_data["quota"] = new_t_money
# 保存被转帐用户的数据
save(t_name, t_data)
print(f"""
用户[{name}的剩余金额为[{new_money}]
用户[{t_name}的剩余金额为[{new_t_money}]]
""")
@outer
def withdraw():
"""提现"""
while True:
name = tag_dict["user"]
money = input("请输入提现金额:").strip()
if money.lower() == "q":
break
data = select(name)
name_money = data["quota"]
new_money = name_money - int(money)
data["quota"] = new_money
save(name, data)
print("用户[{}]提现成功,剩余金额为[{}]".format(name, new_money))
choice_dict = {
"1": register,
"2": login,
"3": select_data,
"4": transfer,
"5": withdraw,
"6": exit,
}
while True:
print("""
1.注册
2.登录
3.查看
4.转账
5.提现
6.退出
""")
choice = input("请输入功能编号:").strip()
if not choice.isdigit():
print("请输入数字")
continue
if choice not in choice_dict:
print("输入的编号不存在")
continue
choice_dict.get(choice)()

浙公网安备 33010602011771号