python(闭包函数与装饰器)
今日内容概要
-
global与nonlocal
-
函数名的多种用法
-
闭包函数
-
装饰器简洁介
-
无参装饰器
-
装饰器模板
-
装饰器语法糖及修复技术
global和nonlocal
money = 666
def index():
global money
money = 123
index()
print(money)
global用于局部名称空间修改全局名称空间(改变的是不可变类型)
nonlocal内层局部名称空间该外层局部名称空间
函数名的多种用法
函数名其实绑定的也是一内存地址,只不过该地址里面存放的不是数据值而是一段代码,函数加括号就会找到该代码并执行,有以下几种执行的方法:
1.可以当做变量名赋值
def index ():pass
res = index
res()
# 把index含参数赋值给res,res就具备的有调用函数的功能
2.可以当做函数的参数
def index():
print('form index')
def func(a):
print(a)
a()
func(index)
# func函数调用index作为参数传给a,a就拥有了index的调用功能
3.可以当函数的返回值
def index():
print('from index ')
def func():
print('from func')
return index
res = func()
print(res)
res()
def index():
print('from index')
def func():
print('from func')
return func
res = index()
print(res)
res()
4.可以当做容器类型(可以存放多个数据的数据类型)的数据
def register():
print('注册功能')
def login():
print('登录功能')
def withdraw();
print('提现功能')
def transfer():
print('转账功能')
def shopping():
print('购物功能')
# 定义功能编号与功能的对应关系
func_dict = {
'1':register,
'2':lodin,
'3':withdarw,
'4':transfer,
'5':shopping
}
while True:
print("""
1.注册功能
2.登录功能
3.提现功能
4.转账功能
5.购物功能
""")
choice = input('请输入你要执行的编号功能:')
if choice in func_dict:
func_name = func_dict.(chioce)
func_name()
else:
print('该功能不存在')
闭包函数
定义 在函数内部的函数,并且用到了外部函数名称空间中的名字闭包就是能够读取其他函数内部变量的函数
作用:
保存外部函数的变量,不会随着外部函数调用完而销毁
闭包的形成条件:
1. 函数嵌套
2. 内部函数必须使用了外部函数的变量或者参数
3. 外部函数返回内部函数 这个使用了外部函数变量的内部函数称为闭包
1.定义在函数内容
2.用到外部函数名称空间中的名字
def index():
name = 'jason'
def inner():
print(name)
闭包函数实际应用》》》:其实就是另外一种函数体代码传参的方式。
1.给函数体代码传参的方式:代码里面缺什么变量名形参里面就补什么变量名
def register(name,age):
print(f"""
姓名:{name}
年龄:{age}
""")
register('jason', 18)
2.给函数体代码传参的方式:闭包函数
def outer(name, age):
# name = 'jason'
# age = 18
def register():
print(f"""
姓名:{name}
年龄:{age}
""")
return register
res = outer('jason', 18)
res()
res()
res = outer('kevin', 28)
res()
装饰器的简介
概念:
# 1.不修改已有函数的源代码
# 2.不修改已有函数的调用方式
# 3.给已有函数增加额外的功能
装饰器的本质:
并不是一门新的技术,而是由函数参数、名称空间、函数多种用法、闭包函数组合到一起的结果。实质上也是一个闭包函数,也就是说,他也是一个函数嵌套。
注意与闭包函数的区别:装饰器实质上是一个闭包函数,但是装饰器这个闭包函数。他的参数有且只有一个并且是函数类型的话,他才是装饰器,否则他就是闭包函数!
口诀:
对修改封闭 对扩展开放
储备知识:
时间的相关操作
import time
print(time.time()) # 时间戳(距离1970-01-01 00:00:00所经历的秒数)
time.sleep(3)
print('三秒过后执行')
举个例子:
count= 0
循环之前先获取时间戳
start_time = time.time()
while count < 100:
print('嘿嘿嘿')
count +=1
end_time = time.time()
print ('循环消耗的时间:',end_time - start_time)
装饰器推导流程
1.直接在调用index函数的前后添加代码
import time
def index():
time.sleep(3)
print('from index')
def home():
time.sleep(1)
print('from home')
start_time = time.time()
index()
end_time = time.time()
print('函数index的执行时间为>>>:', end_time-start_time)
结果:
from index
函数index的执行时间为>>>: 3.012359857559204
2.index调用的地方比较多,代码不可能反复拷贝:这时候就用到了一个能相同的代码在不同的位置反复执行>>>==函数==
import time
def index():
time.sleep(3)
print('from index')
def home():
time.sleep(1)
print('from home')
def get_time():
start_time = time.time()
index()
end_time = time.time()
print('函数index的执行时间为>>>:', end_time - start_time)
get_time()
3.函数体代码写死了,只能统计index的执行时间,如何才能做到统计更多的函数运行时间,直接传参变统计函数
import time
def index():
time.sleep(3)
print('from index')
def home():
time.sleep(1)
print('from home')
def get_time(xxx):
start_time = time.time()
xxx()
end_time = time.time()
print('函数的执行时间为>>>:', end_time - start_time)
get_time(index)
get_time(home)
4.虽然实现了一定的兼容性,但是并不符合装饰器的特征,第一种传参不写,只能考虑闭包
import time
def index():
time.sleep(3)
print('from index')
def home():
time.sleep(1)
print('from home')
def outer(xxx):
# xxx = index
def get_time():
start_time = time.time()
xxx()
end_time = time.time()
print('函数的执行时间为>>>:', end_time - start_time)
return get_time
res = outer(index)
res()
res1 = outer(home)
res1()
5.调用的方式还是不对,使用变量名赋值绑定(*****)
import time
def index():
time.sleep(3)
print('from index')
def home():
time.sleep(1)
print('from home')
def outer(xxx):
def get_time():
start_time = time.time()
xxx()
end_time = time.time()
print('函数的执行时间为>>>:', end_time - start_time)
return get_time
res = outer(index) # 赋值符号的左边是一个变量名 可以随意命名
# res1 = outer(index)
# res2 = outer(index)
# jason = outer(index)
# index = outer(index)
index()
home = outer(home)
home()
结果:
from index
函数的执行时间为>>>: 3.000969648361206
from home
函数的执行时间为>>>: 1.0005121231079102
6.上述装饰器只能装饰无参函数 兼容性太差
import time
def func(a):
time.sleep(0.1)
print('from func', a)
def func1(a,b):
time.sleep(0.2)
print('from func1', a, b)
def func2():
time.sleep(0.3)
print('from func2')
def outer(xxx):
def get_time(a, b):
start_time = time.time()
xxx(a, b)
end_time = time.time()
print('函数的执行时间为>>>:', end_time - start_time)
return get_time
func1 = outer(func1)
func1(1, 2)
# func = outer(func)
# func(1) # 报错
# func2 = outer(func2)
# func2()#报错
7.被装饰的函数不知道有没有参数以及有几个参数 如何兼容
可变长形参
def func(a):
time.sleep(0.1)
print('from func', a)
def func1(a,b):
time.sleep(0.2)
print('from func1', a, b)
def outer(xxx):# (可以装饰任意类型的函数)
def get_time(*args, **kwargs): # 形参 get_time(1,2,3) args=(1,2,3)
start_time = time.time()
xxx(*args, **kwargs) # 实参 xxx(*(1,2,3)) xxx(1,2,3)
end_time = time.time()
print('函数的执行时间为>>>:', end_time - start_time)
return get_time
func = outer(func)
func(123)
func1 = outer(func1)
func1(1, 2) # 这里再执行一遍就可以了
结果:
from func 123
函数的执行时间为>>>: 0.10327482223510742
from func1 1 2
函数的执行时间为>>>: 0.20255112648010254
8.如果被装饰的函数有返回值
def func(a):
time.sleep(0.1)
print('from func', a)
return 'func'
def func1(a,b):
time.sleep(0.2)
print('from func1', a, b)
return 'func1'
def outer(xxx):
def get_time(*args, **kwargs):
start_time = time.time()
res = xxx(*args, **kwargs)
end_time = time.time()
print('函数的执行时间为>>>:', end_time - start_time)
return res
return get_time
# func = outer(func)
# res = func(123)
# print(res)
func1 = outer(func1)
res = func1(123, 123)
print(res) #这里不要让人看到就好了
装饰器模板
# 务必掌握
def outer(func):
def inner(*args, **kwargs):
# 执行被装饰对象之前可以做的额外操作
res = func(*args, **kwargs)
# 执行被装饰对象之后可以做的额外操作
return res
return inner
装饰器语法糖
def outer(func_name):
def inner(*args, **kwargs):
print('执行被装饰对象之前可以做的额外操作')
res = func_name(*args, **kwargs)
print('执行被装饰对象之后可以做的额外操作')
return res
return inner
"""
语法糖会自动将下面紧挨着的函数名当做第一个参数自动传给@函数调用
"""
@outer # func = outer(func)
def func():
print('from func')
return 'func'
@outer # index = outer(index)
def index():
print('from index')
return 'index'
func()
index(