python学习笔记
今日内容概要
- 闭包函数简介
- 闭包函数的实际应用
- 装饰器简介
- 装饰器推导流程(重要)
- 装饰器功能完善
- 装饰器统一使用模板(通用)
- 装饰器语法糖
今日内容详细
闭包函数简介
闭包函数:在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的函数名。这样就构成了一个闭包。
def func(username):
# username = 'jason'
def index():
print(username)
return index
# 思考如何在全局调用index
res = func()
print(res)
res()
func('jason') # username = 'jason'
闭包函数实际应用
1.读取函数内部的变量
2.让函数内部的局部变量始终保持在内存中
一般来说,函数内部的局部变量在这个函数运行完以后,就会被Python的垃圾回收机制从内存中清除掉。如果希望这个局部变量能够长久的保存在内存中,可以用闭包来实现这个功能。
装饰器简介
装饰器不是一个全新知识 而是由我们前两天所讲的函数知识整合到一起的产物
1.装饰器的本质
在不改变被装饰对象原来的'调用方式'和'内部代码'的情况下给被装饰对象添加新的功能
eg:
def func():
print(123)
func() # 每次执行之前需要校验用户身份
2.装饰器的原则
对修改封闭 对扩展开放
3.知识储备
import time
print(time.time()) # 1656987566.7260265
'''时间戳(秒数):当前距离1970年1月1日0时0分0秒所经历的秒数'''
# 实际应用>>>:统计代码的运行时间
start_time = time.time() # 100
for i in range(100000):
print(i)
end_time = time.time()
print('for循环的执行时间是:%s'%(end_time - start_time))
time.sleep(3)
'''让程序原地等待三秒'''
print('睡醒了 还是很懵逼')
装饰器前期推导
import time
def index():
time.sleep(3)
print('from index')
'''统计index函数的执行时间'''
start_time = time.time() # 在调用index函数之前获取一下时间戳
index() # 调用index函数
end_time = time.time()
print(end_time - start_time)
缺陷:
如果有多个index需要统计时间 则需要重复编写代码
解决措施:
封装成函数
def get_time():
start_time = time.time() # 在调用index函数之前获取一下时间戳
index() # 调用index函数
end_time = time.time()
print('函数的执行时间是:',end_time - start_time)
缺陷:
如果有多个不同的函数需要统计时间 那么上述的解决措施不够完善
解决措施:
给函数体添加形参(动态传参)
def home():
time.sleep(5)
print('from home')
def get_time(xxx):
start_time = time.time() # 在调用index函数之前获取一下时间戳
xxx(*args,**kwargs) # 调用index函数
end_time = time.time()
print('函数的执行时间是:',end_time - start_time)
get_time(index)
get_time(home)
缺陷:
不同形参个数的函数无法兼容统计
解决措施:
*args **kwargs
但是在我们目前的代码中无法实现(暂且忽略)
def func1(a):
time.sleep(1)
print('from func1')
get_time(func1)
缺陷:
改变了原来的调用方式
解决措施:
装饰器推导流程
装饰器各种版本
import time
"""针对有参无参函数如何兼容"""
def outer(xxx):
def get_time(*args, **kwargs):
start_time = time.time() # 在调用index函数之前获取一下时间戳
res = xxx(*args, **kwargs) # 调用index函数
end_time = time.time()
print('函数的执行时间是:', end_time - start_time)
return res
return get_time
def home():
time.sleep(2)
print('from home')
return '执行home函数之后的返回值'
def index(name):
time.sleep(1)
print('from index')
return '执行index函数之后的返回值'
home = outer(home)
xxx = home()
print(xxx)
index = outer(index)
res = index('jason')
print(res)
装饰器的固定模板
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
import time
def home():
time.sleep(1)
print('from home')
return 'home返回值'
home = outer(home)
res = home()
print(res)
"""
执行home函数之前需要添加校验用户身份的功能
"""
# 装饰器语法糖
import time
@outer # home = outer(真正的函数名home)
def home():
'''我是home函数 我要热死了!!!'''
time.sleep(1)
print('from home')
return 'home返回值'
help(home)
print(home)
home()
def index():
'我是index函数 我的功能很强大'
pass
# help(index)
作业
1.编写一个用户认证装饰器
基本要求
执行每个函数的时候必须先校验身份 eg: jason
def outer(func_name):
def inner(*args, **kwargs):
'''登录程序'''
username = input('username:').strip()
password = input('password:').strip()
if username == 'jason' and password == '123':
res = func_name(*args, **kwargs)
return res
else:
print('登录失败')
return inner
@outer
def func_name(*args, **kwargs):
print('欢迎你jason')
func_name()
拔高练习(有点难度)
执行被装饰的函数 只要有一次认证成功 那么后续的校验都通过
函数:register login transfer withdraw
提示:全局变量 记录当前用户是否认证
user_login = False
def outer(func_name):
def inner(*args,**kwargs):
'''登录程序'''
global user_login # 将user_login变量设置成全局变量
if user_login:
ret = func_name(*args, **kwargs)
return ret
else:
username = input('username:').strip()
password = input('password:').strip()
if username == 'jason' and password == '123':
user_login = True
ret = func_name(*args, **kwargs)
return ret
else:
print('登录失败')
return inner
@outer
def func_name_1(*args, **kwargs):
print('欢迎你jason')
@outer
def func_name_2(*args, **kwargs):
print('没有验证')
func_name_1()
func_name_2()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了