闭包函数简介
闭包函数:
1.定义在函数内部的函数
2.内部函数使用了外部函数名称空间的名字
ps: 只有上述两个特征的函数才能称之为闭包函数
def func(username):
def index():
print(username)
return index
res = func('jason')
res() #
'''
1.先执行func('jason)函数
2.再执行index()函数,返回index函数名给变量res
3.res()就等于是index(),执行index函数内代码
'''
装饰器简介
"""
装饰器不是一个全新知识,而是我们前面的函数知识的整合
"""
1.装饰器的本质
在不改变被装饰对象原来的'调用方式'和'内部代码'的情况下给被装饰对象添加新的功能
eg:
def func():
print(123)
func() # 每次执行之前需要校验用户身份
2.装饰器的原则
对修改封闭,对扩展开放
3.知识储备
import time
print(time.time()) # 1657005080.087934
'''时间戳(秒数):当前距离1970年1月1日0时0分0秒的距离'''
# 实际运用 >>>:统计代码的运行时间
start_time = time.time()
for i in range(10000):
print(i)
end_time = time.time()
print('for循环10000次的执行时间是:%s' % (end_time-start_time) ) # for循环10000次的执行时间是:0.026255130767822266
time.sleep(3) # 让程序原地等待三秒
装饰器前期推导
import time
def index():
time.sleep(3)
print('from index')
'''1.统计index函数的执行时间'''
# start_time = time.time()
# index()
# end_time = time.time()
# print(end_time-start_time)
'''
缺陷: 如果有多个index需要统计时间,则需要重复编写
解决措施:
封装成函数
'''
#
# def get_time():
# start_time = time.time()
# index()
# end_time = time.time()
# print(end_time-start_time)
# get_time()
'''
缺陷: 如果有多个不同的函数需要统计时间,那么上述的解决措施不够完善
解决措施:
给函数体添加形参(动态传参)
'''
# def home():
# time.sleep(5)
# print('from home')
#
# def get_time(xxx):
# start_time = time.time()
# xxx(*args,**kwargs)
# 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()
res = xxx(*args,**kwargs) # from home # from index
end_time = time.time()
print(end_time-start_time) # 2.0044140815734863 # 3.0019779205322266
return res
return get_time
def home():
time.sleep(2)
print('from home')
return '执行home函数之后的返回值'
def index(name):
time.sleep(3)
print('from index')
return '执行index函数之后的返回值'
home = outer(home)
res1 = home()
print(home) # <function outer.<locals>.get_time at 0x10285be50> # 执行index函数之后的返回值
index = outer(index)
res2 = index('jason')
print(res2)
装饰器固定模版
from functools import wraps
import time
def outer(func_name):
@wraps(func_name)
def inner(*args,**kwargs):
print('执行被装饰对象之前可以做的额外操作')
res = func_name(*args,**kwargs)
print('执行被装饰对象之后可以做的额外操作')
return res
return inner
# def home():
# time.sleep(1)
# print('from home')
# return 'home返回值'
# home = outer(home)
# res = home()
# print(res)
"""
执行home函数之前需要添加校验用户身份的功能
"""
# 装饰器语法糖
@outer
def home():
'''我是home函数'''
time.sleep(1)
print('from home')
return 'home返回值'
home()
# home = outer(home)
# print(home) # <function home at 0x10f436e50>
案例
"""
1.编写一个用户认证装饰器
基本要求
执行每个函数的时候必须先校验身份 eg: jason 123
拔高练习(有点难度)
执行被装饰的函数 只要有一次认证成功 那么后续的校验都通过
函数:register login transfer withdraw
提示:全局变量 记录当前用户是否认证
"""
from functools import wraps
login_result = '' # 全局变量 判断是否登录成功
def outer(func_name):
@wraps(func_name)
def inner(*args,**kwargs):
if login_result == '登录成功':
ret = func_name(*args,**kwargs)
return ret
else:
print('未登录无访问权限')
return inner
def register():
username = input('请输入注册用户名>>>:').strip()
with open(r'user_info','r',encoding='utf8') as file:
for line in file:
if line.strip() != ''.strip(): # 判断文件内是否为空,如不进行判断,下面解压赋值会报错
real_name, real_pwd = line.strip().split('|')
if username == real_name:
print('该用户名已经注册!')
break
else:
password = input('请输入注册密码>>>:').strip()
user_info = f'{username}|{password}\n'
with open(r'./user_info', 'a', encoding='utf8') as file1:
file1.write(user_info)
file1.flush()
print('注册成功')
break
else:
password = input('请输入注册密码>>>:').strip()
user_info = f'{username}|{password}\n'
with open(r'./user_info', 'a', encoding='utf8') as file1:
file1.write(user_info)
file1.flush()
print('注册成功')
break
def login():
username = input('请输入登录账号>>>:').strip()
password = input('请输入登录密码>>>:').strip()
user_info = f'{username}|{password}'
with open(r'./user_info','r',encoding='utf8') as file:
for line in file:
global login_result
if user_info == line.strip():
login_result = '登录成功'
print('登录成功')
global name_book
name_book = username
break
else:
# result = '登录失败'
print('用户名或者密码错误')
import os
@outer
def transfer(): # 只能本人转账给他人,简单实现
name = input('请输入转账人')
money = input('请输入转账金额')
with open('./books','r',encoding='utf8') as file:
item_book ={}
for line in file:
real_name,real_money = line.strip().split('|')
if real_name not in item_book:
item_book[real_name] = real_money
if name in item_book:
with open(r'./books','r',encoding='utf8') as file:
info = file.read()
modify_info = f'{name_book}|{item_book.get(name_book)}'
modify_other = f'{name}|{item_book.get(name)}'
my_money = int(item_book.get(name_book))- int(money)
other_money = int(item_book.get(name)) + int(money)
print(f'您转账给{name}{money}元,余额为:{my_money}')
with open(r'./books','r',encoding='utf8') as file1, open (r'./demo.txt.swap','w',encoding='utf8') as file2:
for line in file1:
if line.strip() == modify_info:
file2.write(line.replace(modify_info,f'{name_book}|{my_money}'))
if line.strip() == modify_other:
file2.write(line.replace(modify_other,f'{name}|{other_money}'))
os.remove('books')
os.rename('./demo.txt.swap','books')
@outer
def withdraw():
print('退出登录成功,请重新登录')
is_withdraw = input('确认要退出登录吗?y 确定退出 ').strip()
global login_result
if is_withdraw == 'y':
login_result = ''
return
func_dict = {
'1':register,
'2':login,
'3':transfer,
'4':withdraw
}
while True:
print("""
1.注册功能
2.登录功能
3.转账功能
4.退出登录功能
""")
func_id = input('请输入功能编号')
if func_id in func_dict:
res = func_dict.get(func_id)
res()