Day 27 函数专题2 装饰器
昨天我们接触到了函数大部分的功能,然后在你日常ctrl点进某个复杂的项目,发现函数上方有一个@xxx,它就是装饰器
装饰器本质上是一个 Python 函数,它可以让其他函数或方法在不需要做任何代码修改的前提下增加额外功能。
--本质是如果让一个函数具备太多功能,那么他看起来就会比较乱,可读性比较差,如果把其中一部分相同甚至可以复用的功能用一个新的函数来调用,然后让2个函数同时实现,就会做到进一步封装了函数的一些用法,做到dry原则(don't repeat yourself),使函数更加具有可读性
所以装饰器本身就是函数中调用其他函数,实现先拆分函数,再合并函数的功能。
普通的函数
下面这个函数实现的是计算2到999999的所有质数(在大于 1 的自然数中,除了 1 和它自身外,不能被其他自然数整除的数),并且打印找到这些数需要的时间
在函数中通过time模块进行记时
会发现,这个time模块让整个代码逻辑很混乱,因为函数的主体是找质数,time模块是找质数的时间,如果可以time模块放在函数外,这样逻辑才清晰
import timedef is_prime(num): if num < 2:return Falsefor i in range(2,int(num**0.5) + 1):if num % i == 0:return Falsereturn Truedef prime_nums():begin_time = time.time()for i in range(2,1000000):is_prime(i) # 就不输出了,避免太多end_time = time.time()print(f"程序运行时间为{end_time - begin_time}秒")prime_nums()
运行结果: 程序运行时间为5.0821802616119385秒
装饰器函数
装饰器函数的参数是另一个函数,返回值也是一个函数;可以参考下方代码,看下优化在哪里。
import time# 定义一个装饰器
def display_time(func):def wrapper(): # 定义一个内部函数,在装饰器中wrapper函数是一个常用的函数名,并非强制,约定俗成的start_time = time.time()func() # 直接调用原函数(无参数),这里的func()是指装饰器需要修饰的函数,在这里是prime_nums()end_time = time.time()print(f"执行时间: {end_time - start_time} 秒")return wrapper # return wrapper是返回函数对象,如果是return wrapper()则是立即执行wrapper函数def is_prime(num): if num < 2:return Falsefor i in range(2,int(num**0.5) + 1):if num % i == 0:return Falsereturn True@display_time #下面这个函数就是display_time的参数(fun)
def prime_nums():for i in range(2,1000000):is_prime(i) # 就不输出了,避免太多prime_nums()
运行结果:执行时间: 4.53002142906189 秒
逻辑上还是一样的,只不过这个把非重点函数的功能装饰起来了,使得我们看到的代码更加清晰明了。
进一步拓展装饰器实现复用
就是说一个装饰器可以被当作多个函数来用,其实就是传参数的问题,默认参数,或者一个、两个参数。
可以看到,上述这个写法的时候,prime_nums()没有传入参数,如果函数有参数,那么必须给外部函数传入参数,也就是需要给外部的装饰器函数传入参数。
那么装饰器函数是需要复用的,不同的内部函数传入的参数不同,那就需要装饰器可以传入可变参数来维持这个特性。这就是说到了我们昨天的可变参数
装饰器函数返回的是wrapper函数,所以,在调用装饰器函数的时候,返回的还是wrapper函数,而不是被修饰的函数。他是被修饰函数的外层函数,参数要大于等于被修饰函数的参数
今日作业
# 作业答案def logger(func):def wrapper(*args, **kwargs): # args 是元组,kwargs 是字典print(f"开始执行函数 {func.__name__},参数: {args}, {kwargs}")result = func(*args, **kwargs)print(f"函数 {func.__name__} 执行完毕,返回值: {result}")return resultreturn wrapper@logger
def multiply(a, b):return a * b multiply(2, 3) # 调用 multiply 函数,观察日志输出
总结
装饰器是 Python 里的语法糖,本质是高阶函数,能在不修改原函数代码和调用方式的前提下,为函数添加额外功能。
它接收一个函数作为参数,返回一个新函数。新函数会包裹原函数,在执行原函数前后添加新逻辑,比如日志记录、性能测试等。使用时,通过 `@` 符号将装饰器应用到目标函数上,提高代码复用性和可维护性,让代码更简洁优雅。