今日内容
闭包函数(重点)
-
特征
1.定义在函数里面的函数 2.函数内部使用了外部函数局部空间的函数名字
只有同时满足这两个特征才叫做闭包函数
eg:
def outer(username):
# username = 'jason'
def inner(): # 嵌套在outer里面的函数
print(username) # 用的是outer局部空间的username
return inner
index = outer()
index() # jason
以上代码同时满足闭包函数的两大特征。
代码执行顺序:
- 闭包函数的实际应用
eg:
def outer(username):
# username = 'jason'
def inner():
print(username)
return inner
index = outer('jason')
index() # jason
index1 = outer('kevin')
index1() # kevin
闭包函数是传参的另一种方式
装饰器(重点)
-
装饰器的本质
在不改变被装饰对象原来的
调用方式
和内部代码
的情况下给函数新增功能以上就是官方一点的说法,装饰器通俗易懂的说,可以类似与你买了一部手机以后,想让它外观看起来更好看一点, 就又给它装了个手机壳。装饰器就可以类比手机壳。
-
原理
对修改封闭,对扩展开放
就是,你给我加功能,我OK;但是想修改,是不能的
eg:
统计函数运行的时间
import time # 导入时间模块
def index():
time.sleep(3) # 让代码在这停留3秒
print('加油!')
start_time = time.time() # 记录运行代码前的时间戳
index() # 调用函数
end_time = time.time() # 记录函数运行结束的时间戳
print(end_time - start_time) # 打印出时间戳差,就是函数运行的时间
补充知识:时间戳(当前时间距离1970年1月1日的秒数)
- 简易版本的装饰器
思考
上述统计函数的运行时间的功能,是不是功能过于单一,但是如果写在函数体内那功能可能就更强大了
根据函数的知识,我们先将功能封装成一个函数,然后往里面传参
eg:
import time
def index():
time.sleep(3)
print('加油!')
def outer(): # 将功能封装为一个函数
start_time = time.time()
index() # 调用函数
end_time = time.time()
print(end_time - start_time)
outer() # 调用功能函数
- 优化版本装饰器
思考:但是这样我们把函数名写死了,就只能运行这一个函数
那我们可以通过传参的形式写活
eg:
import time
def index():
time.sleep(3)
print('加油!')
def home():
time.sleep(3)
print('加油!')
def outer(func): # 写入一个形参
start_time = time.time()
func() # 传入的实参加括号就可以调用相应的函数
end_time = time.time()
print(end_time - start_time)
outer(index) # 传一个实参,传什么形参就是什么
outer(home) # 传一个实参,传什么形参就是什么
输出结果:
加油!
3.000584840774536
加油!
3.0007455348968506
- 进阶版装饰器
思考:这样的话离装饰器的定义已经很像了,但是我们可以发现调用函数的方式发生改变了,index函数是func加括号调用。
解决
通过函数体传参的形式,利用函数名的使用方式
eg:
import time
def index():
time.sleep(3) # 代码停3秒
print('加油!')
def outer(func): # 接收到index
def inner():
start_time = time.time()
func() # 调用正真的函数
end_time = time.time()
print(end_time - start_time)
return inner
index = outer(index) # 先看右边,传一个实参, 狸猫换太子
index() # 这里的index其实是inner,是上面代码接收的返回值
- 完整版本装饰器
根据之前的版本,我们还可以加入参数问题,返回值的问题,进行一个完善,最终生成了完整版本
import time
def index():
time.sleep(3)
print('加油!')
def outer(func):
def inner(*args, **kwargs): # 这里是狸猫换太子的index的形参
start_time = time.time()
res = func(*args, **kwargs) # res接收函数的返回值,这里是正真函数的实参
end_time = time.time()
print(end_time - start_time)
return res # 然后再返回出去
return inner
index = outer(index)
index()
- 装饰器固定模板(记住即可)
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
装饰器语法糖
-
理解
Python给提供了一个装饰函数更加简单的写法,那就是语法糖; 语法糖的书写格式是: @装饰器名字,通过语法糖的方式也可以完成对已有函数的装饰。(定义装饰器)
也就可以把这两步省略掉
index = outer(index)
eg:
def outer(func):
def inner(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
end_time = time.time()
print(end_time - start_time)
return res
return inner
@outer # 相当于是index = outer(index)
def index():
time.sleep(3)
print('加油!')
今日作业
1.编写一个用户认证装饰器
基本要求
执行每个函数的时候必须先校验身份 eg: jason 123
拔高练习(有点难度)
执行被装饰的函数 只要有一次认证成功 那么后续的校验都通过
函数:register login transfer withdraw
提示:全局变量 记录当前用户是否认证
代码:
def outer(func_name):
def inner(*args, **kwargs):
if is_tage: # 通过全局标志位来进行判断
username = input('please input yours username>>>:').strip()
password = input('please input yours password>>>:').strip()
if {'name': username, 'pwd': password} in user_name:
res = func_name(*args, **kwargs) # 接收函数体运行后的返回值
return res
else:
return # 如果判断不正确,直接结束
else:
res = func_name(*args, **kwargs) # 固定模式
return res
return inner
@outer # 相当于join = outer(join)
def join():
# 添加
id = input('请输入你要添加的员工id:')
if id in l1:
print('员工已存在')
return
name = input('请输入员工姓名:')
age = input('请输入员工年龄:')
post = input('请输入员工的职业:')
poy = input('请输入员工的薪资:')
l2 = l1.fromkeys([id], {'name': name, 'age': age, 'post': post, 'poy': poy})
l1.update(l2)
print(f'员工{id}已经添加成功')
@outer
def change():
# 修改
id = input('请输入你想修改薪资员工的编号:')
if id not in l1:
print('员工不存在')
return
l1[id]['poy'] = input('请输入你想修改为多少薪资:')
print(f'员工{id}薪资已修改成功')
@outer
def assign():
# 指定
id = input('请输入你要查看员工的id:')
if id not in l1:
print(f'{id}不存在')
return
print(f'''
----------------------info-------------------------
id:{id}, name:{l1[id]['name']}, age:{l1[id]['age']}, post:{l1[id]['post']}, poy:{l1[id]['poy']}
---------------------------------------------------
''')
@outer
def total():
# 全部
for id in l1:
print(f'''
----------------------info-------------------------
id:{id}, name:{l1[id]['name']}, age:{l1[id]['age']}, post:{l1[id]['post']}, poy:{l1[id]['poy']}
---------------------------------------------------
''')
@outer
def delete():
# 删除
id = input('请输入你要删除员工的编号:')
if id not in l1:
print(f'{id}不存在')
return
l1.pop(id)
print(f'员工{id}已被删除')
data = {'1': join, '2': change, '3': assign, '4': total, '5': delete}
l1 = {'001': {'name': 'jason', 'age': '25', 'post': '讲师', 'poy': '3w'},
'002': {'name': 'kevin', 'age': '28', 'post': '运营', 'poy': '2.5w'}
}
user_name = [
{'name': 'lzq', 'pwd': '123'},
{'name': 'gsy', 'pwd': '520'}
]
is_tage = True
while True:
print('''
1.添加员工信息
2.修改员工薪资
3.查看指定员工
4.查看所有员工
5.删除员工数据
''')
choice = input('please input yours choice>>>:')
if choice in data:
new_data = data.get(choice)
new_data()
is_tage = False # 当成功一次之后,就让其为Flase
elif choice == '6':
print('拜拜了你嘞!')
break
else:
print('你的指令不正确!')
思考中:如何做到,认证失败,后续还可以继续认证