目录
1.装饰器的条件:
有内函数和外函数,外函数必须返回内函数,内函数必须引用外函数的变量
# 定义一个没有功能的装饰器
def runtime(func):
def inner(*args, **kwargs):
pass
return inner
2.装饰器和闭包的异同:
装饰器和闭包在定义上是相同的,但是他们的用法有不同,闭包用于保存函数的上一次运行完的状态,装饰器用于为函数或者类添加额外的功能
3.装饰器的概念:
在不改变函数或者源代码的基础上,为函数添加额外的功能,装饰器的本质就是函数的闭包,他把一个callable对象,作为参数传递
4.例:用装饰器统计函数的执行时间
import time
# 装饰器必须要传入一个callable对象,不然会被认为是闭包
def runtime(func):
# *args, **kwargs 可变长位置参数,可变长关键字参数:同一个位置传递任意个变量,可变长位置参数返回元组,可变长关键字参数返回字典,目的是提高装饰器的通用性
def inner(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
# func.__name__输出函数的名字
print(f"函数{func.__name__}执行了{end-start}s")
return result
return inner
@runtime
def func1(a, b):
# 程序睡一秒再继续运行
time.sleep(1)
return a + b
func1(1, 2)
被装饰过的函数不再是原函数,而是装饰器返回的内函数
时间戳:1970年1月1日0点0分00秒到现在所经历的秒数
5.一个函数可以有多个装饰器:
def log(func):
# @functools.wraps(func)
def inner(*args, **kwargs):
logger.info(f"开始执行{func.__name__}函数")
start = time.time()
time.sleep(2)
result = func(*args, **kwargs) #原函数执行
end = time.time()
print(f"函数执行花了{end-start}s")
logger.info(f"{func.__name__}函数执行结束")
return result
return inner
def runtime(func):
# 保留原数据,将func的数据全部传给inner
@functools.wraps(func)
def inner(*args, **kwargs): # *args **kwargs 让装饰器更加通用
start = time.time()
time.sleep(2)
result = func(*args, **kwargs) #原函数执行
end = time.time()
print(f"函数执行花了{end-start}s")
# print(f"执行了{func.__name__}函数")
return result #inner函数返回原函数的返回值
return inner
@runtime # test_func = runtime(test_func)
@log # test_func = log(test_func)
def func2(a, b):
time.sleep(2)
print("i am func2")
return a+b
函数先执行log装饰器,再执行runtime装饰器,runtime装饰器接受的是log的inner函数,但是python有一个functools,用于将原来的函数的数据传递给装饰器
5.带参数的装饰器
# 带参装饰器
def deco(username, passwd):
def runtime(func):
def inner(*args, **kwargs):
if username in user and passwd == user[username]:
if username == "root":
print("登录成功")
result = func(*args, **kwargs)
print(f"执行了{func.__name__}函数")
return result
else:
print("用户没有权限")
else:
print("用户名或者密码输入错误,不能执行add函数")
return inner
return runtime
@deco(username="root", passwd="123456")
# @deco(username="admin", passwd="admin123")
# @deco(username="admin", passwd="123456")
def add(a, b):
time.sleep(1)
return a + b
add(1, 2)
带参数的装饰器有三层函数,不带参数的装饰器只有两层函数
6 .用类实现装饰器
# 带参数的装饰器,
class A:
def __init__(self, username):
self.username = username
def __call__(self, func):
def inner(*args, **kwargs):
print("this is call>>")
result = func(*args, **kwargs)
return result
return inner
# a = A(usernaem="root"), func1 = a(func1)
@A(username="root")
def func1():
time.sleep(1)
print(" i am func1")
被类装饰器装饰后的函数,不再是原来的函数,而是类A的call方法返回的inner函数
7.装饰类
def outer(cls):
def inner(*args, **kwargs):
print(f"this is class {cls.__name__}")
return cls(*args, **kwargs)
return inner
@outer # A = outer(A) 被装饰完的A是outer的内函数
class A:
def __init__(self, name):
self.name = name
a1 = A("sc")