一,闭包条件
1,函数中嵌套函数
2,外层函数返回内层嵌套函数名
3,内层嵌套函数有引用外层的一个非全局变量,内部嵌套函数不能引用全局变量
二,作用
实现数据的锁定,提高稳定性 通过
index = login(index)
index.__closure__可以查看对外层非全局变量的引用
三,装饰器的实现
开放封闭原则:软件应该是可扩展的,而不可修改
def index(): pass
需求:需要对index加校验功能,但由于开放封闭原则,因此不能直接修改index函数
# 外层函数参数是被装饰的函数
def login(index): def func(): # 校验功能 pass # 放入被装饰的函数 index() # 外层函数返回值是内层函数 return func
执行:
#@login 语法糖 index = login(index)
# index .__closure__ 这里面存储了内部函数调用外部函数的变量,也就是index函数
@login def index(): pass
四,装饰器的作用
在不更改原功能函数内部代码,并且不改变调用方法的情况下为原函数添加新功能。
五,装饰器的应用场景
1,登录验证
2,函数运行时间统计
3,执行函数之前做准备
4,执行函数后清理工作
六,通用装饰器
如果同一个装饰器既要装饰有参数的函数,又要装饰无参数的函数,那么我们在传参的时候就设置成不定长参数,这样不管被装饰的函数有没有参数都能用
def f1(func): def fun(*args, **kwargs): print('执行装饰器中的函数') func(*args, **kwargs) return fun @f1 def func(a, b): print('执行函数--func') print(a + b) func(10, 20)
七,类装饰器
前面是用闭包函数实现的装饰器,也可以使用类当作一个装饰器。
把类当作装饰器有两步操作:
1,首先在__init__方法中,把装饰器函数赋值给一个实例属性
2,然后在类里面实现一个__call__方法,在call方法中调用原来的函数
def add(func): def fun(*args, **kwargs): print('装饰器的功能代码:登录') return func(*args, **kwargs) return fun # myClass = login(MyClass) @login class MyClass: def __init__(self): pass
八,装饰器装饰类
注意:装饰器装饰类fun中的return必须要写,因为类需要把对象返回出来,装饰函数的话return不一定要写
def add(func): def fun(*args, **kwargs): print('装饰器的功能代码,登录验证') return func(*args, **kwargs) return fun @add # MyClass = add(MyClass)----返回fun class MyClass: def __init__(self, name, age): self.name = name self.age = age # 相当于fun('小鱼', 18),fun函数中如果没有return 那么该函数默认返回None,装饰之后该类不能创建对象了 m = MyClass('小鱼', 18) print(m)
九,多个装饰器装饰同一个函数
从下往上装饰,装饰顺序:@decorator -> @login_check
从上往下执行,执行顺序:@login_check -> @decorator -> login()函数
import time
def decorator(func):
def count_time(*args, **kwargs):
print('进入计算时间的装饰器')
start_time = time.time()
func()
end_time = time.time()
spend_time = end_time - start_time
print('函数运行的时间为:',spend_time)
return count_time
with open(file='d:\login.txt', mode='r+', encoding='utf-8') as f:
data = eval(f.read())
def login_check(func):
def ado(*args, **kwargs):
print('进入登录校验装饰器函数')
if data.get('token') is not True:
print(data.get('token'))
n = input('请输入名字:')
p = input('请输入密码:')
if data.get('name') == n and data.get('passwd') == p:
data['token'] = True
func(*args, **kwargs)
else:
print('输入错误')
else:
func(*args, **kwargs)
return ado
@login_check #login = login_check(login) login指向ado函数
@decorator # login = decorator(login) login指向count_time函数
def login():
time.sleep(3)
print('这是需要被装饰的函数')
login()
十,类中三个装饰器
类方法:类 实例对象都可以调用
实例方法:类不能调用 实例可以调用
静态方法:类 实例对象都可以调用
class MyTest():
def __init__(self,name):
self.name = name @classmethod # 被classmethod装饰后,该方法是个类方法 def add(cls): # cls代表类本身 print('add') print(cls) def sub(self): # self代表实例本身 print(self)
@staticmethod
def static(): # 静态方法是没有参数的
pass
@property
def read_attr(self): # 设置只读属性,防止被串改,可以像属性一样调用,注意,这里的属性不能修改,init中的属性可以被修改
return '18' t = MyTest() t.add() # 类属性 类方法可以被实例调用 t.sub() #
t.static() # 静态方法可以被类调用
t.read_attr # t.read_attr()错误 MyTest.add() # MyTest.sub() # 错误,实例方法不能被类调用
MyTest.static() #静态方法可以被类调用