装饰器+闭包+递归 掌握(python一大重要功能)
目录
global与nonlocal
global # 提升全局变量关键字,在函数内使用
name = '123'
def func()
name = '1111'
func()
print(name) # 123
可变数据类型可以在函数内直接修改不要提升全局变量关键字就可以使用
a = [1,2,3]
def func()
a.append(4)
func()
print(a) [1,2,3,4]
# 在不重新修改命名空间变量赋值的情况下,更改数据值
name = '123'
def func():
global name
name = 'zhang'
func()
print(name) # zhang
nonlocal # 嵌套函数内使用外部函数变量,在函数嵌套内使用
def outer():
name = '123'
def index():
name = '111'
print(name) # '123'
def outer():
name = '123'
def index():
nonlocal name
name = '111'
print(name) # '111'
函数名的多种用法
1.当作数据值
def func():
print(123)
func2 = func
print(fun2) # <function func2 at 0x000001D4D4069A60>
2.当作参数传递
def func1():
print(1)
def func2(v1):
print(v1)
func2(func1) # <function func1 at 0x000002540EDF9A60>
3.当作返回值
def func1():
print(1)
def func2():
print(123)
return func1
res = func2()
print(res) # 123 <function func1 at 0x0000013B51BE9A60>
4.当做容器的数据值
def register():
print('注册')
def login():
print('登录')
def withdraw():
print('提现')
def transfer():
print('转账')
def shopping():
print('购物')
d1 = {
'1':register,
'2':login,
'3'withdraw,
'4':transfer,
'5':shopping
}
while True:
choice = input('选着编号')
if choice not in d1;
print('功能不存在')
res = d1.get('choie')
res()
闭包函数
闭包的定义:
1.在函数内定义函数
2.使用外部变量名
例如
def outer():
name = '123'
def inner():
print(name)
# 尽管没有调用,也叫闭包,因为函数在定义的时候就已经确定了名字查找顺序了
闭包的应用场景:
是另外一种给函数传参的方式
给函数传值的方式一:
直接传递参数
def func(a):
print(a)
func(123)
给函数另一种方式二:
闭包传值
def func():
name = '123'
pwd = '456'
def func2():
print(name,pwd)
func2()
func() # 123 456 # 写死了不好
# 可以这样
def func(name,pwd):
def inner()
print(name,pwd)
func(zhang,123) # zhang 123
name = '123'
def func1():
print(name)
def func2():
name = 111
func1()
func2() # 123 函数调用使用变量名,跟在哪调用没关系,而是跟函数定义时的位置有关系
装饰器简介
1.概念
在不改变原有功能和调用方式的前提下实现新增功能
2.本质
装饰器并不是一们新的技术,而是由函数,参数,返回值,变量名,命名空间,函数名多种用法,闭包组合到一起的结果
3.口诀
对修改封闭 对扩展开放
4.超前知识time模块
time模块
如何导入模块
1.import 模块名
2.from 模块名 import 类\函数
time模块的使用
import time
time.time() # 获取当前时间距1970 1 1 0:0 的时间为浮点型 1665475010.6782117
time.sleep(0.5) # 运行到这一行暂停0.5秒
装饰器推导
import time
def func():
time.sleep(0.5)
print('func')
start_time = time.time()
func()
end_time = time.time()
print(f'运行函数耗时{end_time-start_time}') # 运行函数耗时0.5023610591888428
# 如果需要在多个地方统计这一个函数就需要多次写了,太麻烦了
# 我直接科技很活 我闭包在套一层,先试一下
def func():
time.sleep(0.5)
print('func')
def func2():
start_time = time.time()
func()
end_time = time.time()
print(f'运行函数耗时{end_time-start_time}')
func2()
func2()
# 哦可以了方便了
# 现在我又新的需求了,有好多个函数需要及时,这个时候怎么办,
# 我直接写多个函数,用来了用,感觉还是太麻烦了,诶,我想到了,可以直接把,需要统计的函数名,我直接传递给这个让他来,这样就不要写多个了,方便哈哈哈哈。试一下
def func1():
time.sleep(0.5)
print('func1')
def func2():
time.sleep(0.5)
print('func2')
def outer(funcs):
start_time = time.time()
funcs()
end_time = time.time()
print(f'运行函数耗时{end_time-start_time}')
outer(func1)
'''
func1
运行函数耗时0.5023987293243408
'''
outer(func2)
'''
func2
运行函数耗时0.514385461807251
'''
# 这样是可以了但是改变调用了啊
# 嗯对,我在改改,那我再套一程把他返回出去
def func1():
time.sleep(0.5)
print('func1')
def func2():
time.sleep(0.5)
print('func2')
def outer(funcs):
def inner():
start_time = time.time()
funcs()
end_time = time.time()
print(f'运行函数耗时{end_time-start_time}')
return inner # 返回的是inner 的内存地址
func1 = outer(func1) # 这样就修改了变量名的绑定了,看起来就跟原来一样了,狸猫换太子
func1() # 其实是调用inner的内存地址存放的代码
'''
func1
运行函数耗时0.5052452087402344
'''
func2 = outer(func2)
func2()
'''
func2
运行函数耗时0.5050647258758545
'''
# 嗯very good 很好 但是我现在我给你个函数需要一个参数,你在这样还可以吗?
# 我逝一下
'''
def func1(a):
time.sleep(0.5)
print('func1')
def func2():
time.sleep(0.5)
print('func2')
def outer(funcs):
def inner():
start_time = time.time()
funcs()
end_time = time.time()
print(f'运行函数耗时{end_time-start_time}')
return inner # 返回的是inner 的内存地址
func1 = outer(func1) # 这样就修改了变量名的绑定了,看起来就跟原来一样了
func1() # 其实是调用inner的内存地址存放的代码
TypeError: func1() missing 1 required positional argument: 'a'
'''
#啊寄,报错了,我看看什么错,哦原来是需要一个参数,让我see 一 see 怎么解决,
# 既然你需要,那我就直接给你
'''
def func1(a):
time.sleep(0.5)
print('func1')
def outer(funcs):
def inner(a): # 我给你
start_time = time.time()
funcs()
end_time = time.time()
print(f'运行函数耗时{end_time-start_time}')
return inner
func1 = outer(func1) # 这样就修改了变量名的绑定了,看起来就跟原来一样了
func1(1) # 其实是调用inner的内存地址存放的代码
TypeError: inner() missing 1 required positional argument: 'a'
'''
# 欸还是寄,怎么回事,哦没给原来的传啊,好的我加上
def func1(a):
time.sleep(0.5)
print('func1',a)
def func2(aa,bb):
time.sleep(0.5)
print('func2',aa,bb)
def outer(funcs):
def inner(a):
start_time = time.time()
funcs(a) #这里我加上
end_time = time.time()
print(f'运行函数耗时{end_time-start_time}')
return inner
func1 = outer(func1) # 这样就修改了变量名的绑定了,看起来就跟原来一样了
func1(1) # 其实是调用inner的内存地址存放的代码
'''
func1 1
运行函数耗时0.5107102394104004
'''
func2 = outer(func2) # 这样就修改了变量名的绑定了,看起来就跟原来一样了
func2(1,2) # 其实是调用inner的内存地址存放的代码
'''
TypeError: inner() takes 1 positional argument but 2 were given
'''
#很好,成功啦,但没完全成功
#我再想想,想到了,可以用上次说到的,可变长形参呀,还有可变长实参。这样就可以了呀,好的,开始写代码
def func1(a):
time.sleep(0.5)
print('func1',a)
def func2(aa,bb):
time.sleep(0.5)
print('func2',aa,bb)
def outer(funcs):
def inner(*args,**kwargs):
start_time = time.time()
funcs(*args,**kwargs) #这里我加上
end_time = time.time()
print(f'运行函数耗时{end_time-start_time}')
return inner
func1 = outer(func1) # 这样就修改了变量名的绑定了,看起来就跟原来一样了
func1(1) # 其实是调用inner的内存地址存放的代码
'''
func1 1
运行函数耗时0.5107102394104004
'''
func2 = outer(func2) # 这样就修改了变量名的绑定了,看起来就跟原来一样了
func2(1,2) # 其实是调用inner的内存地址存放的代码
'''
func2 1 2
运行函数耗时0.5015923976898193
'''
# 嘿嘿嘿,成功啦,成功啦,完全成功了
# 别高兴太早了,我还有需求呢,我有个函数有返回值,你看你的还能用吗?
def func1(a):
time.sleep(0.5)
print('func1',a)
def func2(aa,bb):
time.sleep(0.5)
print('func2',aa,bb)
def func3(ab,ac):
print('func3',ab,ac)
return ab
def outer(funcs):
def inner(*args,**kwargs):
start_time = time.time()
funcs(*args,**kwargs) # 这里我加上
end_time = time.time()
print(f'运行函数耗时{end_time - start_time}')
return inner
func1 = outer(func1) # 这样就修改了变量名的绑定了,看起来就跟原来一样了,
func1(1) # 其实是调用inner的内存地址存放的代码
'''
func1 1
运行函数耗时0.5107102394104004
'''
func2 = outer(func2) # 这样就修改了变量名的绑定了,看起来就跟原来一样了
func2(1,2) # 其实是调用inner的内存地址存放的代码
'''
func2 1 2
运行函数耗时0.5015923976898193
'''
func3 = outer(func3)
res = func3('a','b') # 接收返回值啊
'''
None
'''
print(res)
# 额,好像不太行啊,我see see 该怎么做
# 那我可以直接接收真实函数的返回值,然后我再通过狸猫换太子的方式,我给再给他,返回出去啊,ok,想到了就要搞,开搞
def func1(a):
time.sleep(0.5)
print('func1',a)
def func2(aa,bb):
time.sleep(0.5)
print('func2',aa,bb)
def func3(ab,ac):
print('func3',ab,ac)
return ab
def outer(funcs):
def inner(*args,**kwargs):
start_time = time.time()
res = funcs(*args,**kwargs) # 这里我加上
end_time = time.time()
print(f'运行函数耗时{end_time - start_time}')
return res
return inner
func1 = outer(func1) # 这样就修改了变量名的绑定了,看起来就跟原来一样了,
func1(1) # 其实是调用inner的内存地址存放的代码
'''
func1 1
运行函数耗时0.5107102394104004
'''
func2 = outer(func2) # 这样就修改了变量名的绑定了,看起来就跟原来一样了
func2(1,2) # 其实是调用inner的内存地址存放的代码
'''
func2 1 2
运行函数耗时0.5015923976898193
'''
func3 = outer(func3)
'''
运行函数耗时0.0
a
'''
# ok完成了。
# 结束但是还可以优化,下次再讲吧
装饰器模板
def outer(func):
def inner(*args,**kwargs):
res = func(*args,**kwargs)
return res
return inner
res = outer(func)
装饰器语法糖
def outer(func):
def inner(*args,**kwargs):
name = input('用户名')
if name == 'zhang':
res = func(*args,**kwargs)
return res
else:
print('姓名不对')
return inner
@outer # 语法糖
def func1(v1):
print('func1',v1)
多层装饰器
def outer_1(func):
print('加载1')
def inner1(*args, **kwargs):
print('执行1')
res = func(*args, **kwargs)
return res
return inner1
def outer_2(func):
print('加载2')
def inner2(*args, **kwargs):
print('执行2')
res = func(*args, **kwargs)
return res
return inner2
def outer_3(func):
print('加载3')
def inner3(*args, **kwargs):
print('执行3')
res = func(*args, **kwargs)
return res
return inner3
@outer_1
@outer_2
@outer_3
def funcs():
print('funcs')
'''
加载是从下往上加载,执行时,从上向下执行
也就是,想先执行哪个装饰器,就要离被,装饰的函数远,
哪个装饰器越靠后执行,就里被装饰的函数近
'''
funcs()
'''
运行顺序
加载3
加载2
加载1
执行1
执行2
执行3
funcs
'''
有参装饰器
def modul(mo):
def outer(func):
def inner(*args,**kwargs):
if mo == '1':
#执行前的
res = func(*args,**kwargs)
return res
return
return inner
return outer
@modul('1')
def func():
print('func')
func()
'''func'''
def modul(mo,bb):
def outer(func):
def inner(*args,**kwargs):
if mo == '1':
#执行前的
res = func(*args,**kwargs)
return res
if bb == '2':
print('哈哈哈哈')
return
return inner
return outer
@modul('1','2') # 在装饰器的时候,有函数调用,函数调用优先级最高所有,modul('1','2') 执行完后就变成了@outer,也就变成了,普通装饰器了
def func():
print('func')
func()
'''哈哈哈哈'''
装饰器模板
# 简单装饰器
def outer(func):
def inner(*args, **kwargs):
print('被装饰函数执行前执行的代码')
res = func(*args, **kwargs)
print('被装饰函数执行后执行的代码')
return res
return inner
@outer
def func1():
print('111')
func1()
'''
被装饰函数执行前执行的代码
111
被装饰函数执行后执行的代码
'''
# 多层装饰器
def modul(var):
def outer(func):
def inner(*args, **kwargs):
print('被装饰函数执行前执行的代码')
res = func(*args, **kwargs)
print('被装饰函数执行后执行的代码')
return res
return inner
return outer
@modul('1')
def func2():
print('222')
func2()
'''
被装饰函数执行前执行的代码
222
被装饰函数执行后执行的代码
'''
装饰器修复
def outer(func):
def inner(*args, **kwargs):
res = func(*args, **kwargs)
return res
return inner
@outer
def func():
print('func')
help(func)
'''
Help on function inner in module __main__:
inner(*args, **kwargs)
'''
#可以被发现
#修复
from functools import wraps
def outer(func):
@wraps(func)
def inner(*args, **kwargs):
res = func(*args, **kwargs)
return res
return inner
@outer
def func():
print('func')
help(func)
'''Help on function func in module __main__:
func()
'''
#完美狸猫换太子
递归函数
#循环调用自己
def func():
print('1')
func() # 自己死循环调用自己,在运行差不多1000左右后,因为,一直在开辟,局部命名空间占用大量内存,解释器为了系统安全,会强制抛出异常终止程序
func()
#互相调用
def func()
print('1')
index()
def index()
print('2')
func()
func()# 互相调用对方死循环相互调用,在运行差不多1000左右后,因为,一直在开辟,局部命名空间占用大量内存,解释器为了系统安全,会强制抛出异常终止程序
作业1
'''
1.编写一个用户认证装饰器
函数:register login transfer withdraw
基本要求
执行每个函数的时候必须先校验身份 eg: jason 123
拔高练习(有点难度)
执行被装饰的函数 只要有一次认证成功 那么后续的校验都通过
提示:全局变量 记录当前用户是否认证
'''
import os
DB = os.path.join(os.path.dirname(__name__), 'db', 'user.txt')
if not os.path.exists(os.path.join(os.path.dirname(__name__), 'db')):
os.makedirs(os.path.join(os.path.dirname(__name__), 'db'))
if not os.path.exists(DB):
f = open(DB,'w',encoding='utf-8')
f.close()
admin_id = {
'name': 'jason',
'pwd': '123'
} # 身份验证
isadmin = [] # 是否成功验证
islogin = [] # 是否成功登录
def is_admin(): # 校验身份
print('还没有校验身份,输入!!')
while True:
name = input('请输入身份用户(q\Q退出)')
if name.upper() == 'Q':
return
pwd = input('请输入身份密码')
if name == admin_id['name'] and pwd == admin_id['pwd']:
isadmin.append(name)
print('身份验证成功,请重新选择功能')
break
print('身份验证失败')
def outer_login(func): # 校验登录装饰器
def inner(*args, **kwargs):
if islogin:
res = func(*args, **kwargs)
return res
else:
print('未登录,请先登录')
return inner
def outer_admin(func): # 校验身份装饰器
def inner(*args, **kwargs):
if isadmin:
res = func(*args, **kwargs)
return res
else:
is_admin()
return inner
def insert_user_info(username, userpwd, money=1000):
'''
向数据库插入用户信息
:param username: 用户名
:param userpwd: 密码
:param money: 金额
:return:
'''
if select_by_username(username):
return False
with open(r'db\user.txt', 'at', encoding='utf-8') as f:
f.write(f'{username}|{userpwd}|{money}\n')
f.flush()
return True
def update_user_info(userinfo, data_all):
'''
更新用户信息
:param userinfo: 更新后的用户信息
:param data_all: 更新前的用户信息
:return:
'''
f1 = open(r'db\user.txt', 'rt', encoding='utf-8')
file_list = f1.readlines() # 一次读取所有行,按行形成一个列表
with open(r'db\user.txt', 'wt', encoding='utf-8') as f2:
f1.close()
user_index = file_list.index(data_all) # 查找更新前,用户信息的位置索引
file_list[user_index] = userinfo # 按索引修改更新后的,用户信息
f2.writelines(file_list) # 把所有信息一次写入文件
return True
def select_by_username(username):
'''
查找用户是否存在
:param username: 要查找的用户名
:return:
'''
with open(r'db\user.txt', 'rt', encoding='utf-8') as f:
for i in f:
if i.strip().split('|')[0] == username: # 查找成功
return i # 返回这个用户的所有信息
else:
return False
def is_login(username, userpwd):
'''
判断是否登录核心功能
:param username: 用户名
:param userpwd: 密码
:return:
'''
data = select_by_username(username)
if not data: # 判断用户是否存在
return False
data = select_by_username(username).strip().split('|') # 分隔字符串用户信息,成列表
if data[0] == username and data[1] == userpwd:
return True
else:
return False
def is_withdraw(money):
'''
提现核心功能
:param money: 提现金额
:return:
'''
username = islogin[0]
data_all = select_by_username(username)
data = data_all.strip().split('|')
if int(data[2]) > money: # 判断剩余金额是否大于提现金额
data[2] = str(int(data[2]) - money) # 提现后剩余的金额
userinfo = '|'.join(data) + '\n' # 再次转成字符串,以便存到数据库里
update_user_info(userinfo, data_all) # 更新用户信息
print(f'提现{money}元成功,剩余金额{data[2]}元')
return True
else:
print('余额不足')
return False
def is_tansfer(tansfer_username, money):
'''
转账核心功能
:param tansfer_username: 要转账用户
:param money: 金额
:return:
'''
username = islogin[0]
transfer_user_all = select_by_username(tansfer_username) # 获取要转账的所有用户信息
if not transfer_user_all: # 查找要转账的用户是否存在
print('要转账的用户不存在')
return False
if tansfer_username == username: # 判断是否转账给自己
print('不能给自己转账')
return False
transfer_user_list = transfer_user_all.strip().split('|')
username_all = select_by_username(username)
username_list = username_all.strip().split('|')
if int(transfer_user_list[2]) > money: # 剩余金额是否大于要转账的金额
transfer_user_list[2] = str(int(transfer_user_list[2]) - money)
username_list[2] = str(int(username_list[2]) + money)
transfer_user_info = '|'.join(transfer_user_list) + '\n'
username_info = '|'.join(username_list) + '\n'
update_user_info(transfer_user_info, transfer_user_all)
update_user_info(username_info, username_all)
print(f'转账给{tansfer_username}金额{money}元成功,剩余金额{transfer_user_list[2]}元')
return True
else:
print('余额不足,无法转账')
return False
@outer_admin
def register():
'''
注册
:return:
'''
while True:
username = input('请输入用户名(q\Q退出)')
if username.upper() == 'Q':
return
useepwd = input('请输入密码')
if insert_user_info(username, useepwd):
print('注册成功')
else:
print('用户名已存在')
@outer_admin
def login():
'''
登录
:return:
'''
while True:
username = input('请输入用户名(q\Q退出)')
if username.upper() == 'Q':
return
useepwd = input('请输入密码')
if is_login(username, useepwd):
islogin.append(username)
print('登录成功')
return
else:
print('用户名或密码错误')
@outer_admin
@outer_login
def withdraw():
'''
提现
:return:
'''
while True:
money = input('请选择提现金额(q\Q退出)')
if money.upper() == 'Q':
return
if not money.isdecimal():
print('请输入纯数字')
continue
is_withdraw(int(money))
@outer_admin
@outer_login
def transfer():
'''
转账
:return:
'''
while True:
transfer_username = input('请输入要转账的用户(q\Q退出)')
if transfer_username.upper() == 'Q':
return
money = input('请输入转账金额')
if not money.isdecimal():
print('请输入纯数字')
continue
is_tansfer(transfer_username, int(money))
@outer_admin
def logout():
'''
退出登录
:return:
'''
if islogin:
islogin.clear()
print('退出成功')
else:
print('您还没有登录')
func_dict = {
'1': ['注册', register],
'2': ['登录', login],
'3': ['提现', withdraw],
'4': ['转账', transfer],
'5': ['注销', logout],
'6': ['退出', exit] # 退出登录
}
def run():
while True:
for k, v in func_dict.items():
print(k, v[0])
choice = input('请输入功能编号')
if choice not in func_dict:
print('输入编号功能不存')
continue
func_dict.get(choice)[1]()
if __name__ == '__main__':
run() # 入口
作业2
# aa = [[15], 1, [2, [3, [4, [5, [6, [7, [8, 9, [10]]]]]]], 11, 12], 13, 14]
# 循环遍历所有元素
from collections.abc import Iterable
aa = [[15], 1, [2, [3, [4, [5, [6, [7, [8, 9, [10]]]]]]], 11, 12], 13, 14]
def func(lists): # 深度优先搜索
for i in lists:
if isinstance(i, Iterable): # 升级版,可以循环可迭代对象 #只能判断列表 if type(i) == list
func(i)
else:
print(i)
func(aa)
def func(lt): # 广度优先搜索
for i in lt:
if not isinstance(i, Iterable): # if type(i) != list:
print(i)
for i in lt:
if isinstance(i, Iterable): # if type(i) == list:
func(i)
func(aa)