修饰器(语法糖)
在python中函数实际上就是一个对象
def outer(x):def inner(y):return x + yreturn innerprint(outer(6)(5))
def double(x):return x * 2
def triple(x):return x * 3def calc_number(func, x):print(func(x))calc_number(double, 3)
calc_number(triple, 3)
函数自己也可以作为返回值
修饰器
新的代码需要在一个函数的前面或者后面添加一段代码
def dec(f):pass@dec
def double(x):return x * 2#等价于
double = dec(double)
会把下面的函数传给这一个装饰器函数, 装饰器需要返回新的函数, 这一个返回值会成为新的下面的函数
import time def timeit(f):def wrapper(x):start = time.time()ret = f(x)print(time.time() - start)return retreturn wrapper@timeit
def myfunction(x):time.sleep(x)# myfunction(1)@timeit
def other_func(x):return x*2print(other_func(2))
带参数
import time
def timeit(f):def wrapper(*args, **kwargs): #传入的参数不限制start = time.time()ret = f(*args, **kwargs) # 会把传入的函数在这里执行print(time.time() - start)return retreturn wrapper@timeit
def myfunc(x):time.sleep(x)@timeit
def add(x, y):return x+yprint(add(2, 3))
接下来就讲装饰器,其实装饰器就是一个闭包,装饰器是闭包的一种应用。什么是装饰器呢,简言之,python装饰器就是用于拓展原来函数功能的一种函数,这个函数的特殊之处在于它的返回值也是一个函数,使用python装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能。使用时,再需要的函数前加上@demo即可。
import timedef timeit(repeats):def decorator(func):def wrapper(*args, **kwargs):total_time = 0for _ in range(repeats): # 1000决定这一个函数的执行次数start_time = time.time()result = func(*args, **kwargs) # 获取一个resultend_time = time.time()total_time += end_time - start_timeaverage_time = total_time / repeatsprint(f"Average execution time: {average_time} seconds")return resultreturn wrapperreturn decorator@timeit(1000)
def double(x):return x * 2# Equivalent to:
# double = timeit(1000)(double)# Test the function
print(double(2))
前面的返回的是一个函数(这一个函数会被作为修饰器), 返回的这一个修饰器调用double再返回一个实际可以执行的函数
修饰器闭包
import time
def timeit(interation):def inner(f):def wrapper(*args, **kwargs):start = time.time()for _ in range(interation):print("1")ret = f(*args, **kwargs)ret = f(*args, **kwargs)print(time.time() - start)return retreturn wrapperreturn inner@timeit(10)
def double(x):return x*2print(double(2))
等价于
inner = timeit(10) # 返回一个修饰器 double = inner(double) # 使用这一个修饰器进行修饰
import timedef inner(f):def wrapper(*args, **kwargs):start = time.time()for _ in range(10):print("1")ret = f(*args, **kwargs)ret = f(*args, **kwargs)print(time.time() - start)return retreturn wrapperreturn inner@inner def double(x):return x*2
装饰器实际装饰的时间是在python解析到这一个函数的时候, 实际执行函数的时候不用再次装饰
实际这一个装饰就是一个闭包, 不同的是这一个闭包对它的参数的使用, 修饰器把这一个参数作为可调用的对象使用
多次修饰
def makeBlod(fn):def wrapped():return "<b>" + fn() + "</b>"return wrappeddef makeItalic(fn):def wrapped():return "<i>" + fn() + "</i>"return wrapped@makeBlod
@makeItalic
def hello():return "hello world"print(hello())
PS E:\JHY\python\2024-4-22> python -u "e:\JHY\python\2024-4-22\main.py" <b><i>hello world</i></b>
装饰的时候会先调用离得近的那一个
类为装饰器
import time
class Test(object):def __init__(self, func):print("初始化")print("func name is %s" % func.__name__)self.__func = funcdef __call__(self):print("装饰器中的功能")self.__func()@Test
def test():print("test函数")test()
这一个实际调用的时候是
test = Test(test)
, 创建了一个对象
import time
class Test(object):def __init__(self, num):print("初始化")self.__num = numdef __call__(self, func):print("装饰器中的功能")def inner():print("inner函数, num = %d" % self.__num)func()return inner@Test(10)
def test():print("test函数")test()
这里是先获取一个对象, 这一个对象的执行是一个修饰器
class Test(object):def __init__(self, num):print("初始化")self.__num = numdef __call__(self, func):print("装饰器中的功能")self.__func = funcreturn self.call_old_funcdef call_old_func(self):print("inner函数")self.__func()