篇幅太长,截取三页目录,需要的看我简介加V获取
- 装饰器
“””在这之前小北想说为什么要使用装饰器:因为优雅”””
-
- 装饰器概念
装饰器是 Python 中用于修改函数或类的语法结构的工具(元类也可以修改类,不过一般推荐使用装饰器来修改类)。它是一种以函数作为输入参数,并返回一个函数作为输出的函数,可以在不改变原有函数代码的情况下,给函数增加一些功能或者改变函数的行为。
装饰器的使用方式是在函数定义的上方使用 @decorator_name 的形式将装饰器应用到函数上,这样定义的函数在被调用时会先执行装饰器函数,再执行原始函数。常见的装饰器有类装饰器、函数装饰器、属性装饰器等。
装饰器本身需要接受一个被装饰的对象作为参数,该参数通常为函数、方法、类等对象。
装饰器需要返回一个对象,该对象可以是 经过处理的原参数对象、一个包装且类似原参数的对象;或者返回一个不相干内容(通常不建议使用)
1.2、装饰器类型介绍【前三是最常用的】
1.2.1最简单的装饰器
# 在调用函数前后都输出一行文字
def my_decorator(func):
def wrapper():
print("Before the function is called.")
func()
print("After the function is called.")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
解释:
- 当我们调用被装饰器修饰的函数的时候,首先会把say_hello的函数传入my_decorator的func参数中,然后再去执行内部的wrapper函数(在这个函数内部就会操作很多东西,比如增删改等操作),最后返回wrapper函数。
- 实际上我们调用的say_hello函数没有被执行,那这里为什么执行了呢?是因为wrapper函数里面又调用了一次它,如果不调用,那么say_hello函数就是一个装饰,但是通常情况下都会调用一次来达到我们的一些特殊目的。
1.2.2.用于修改对象和函数的装饰器
1.2.3.用于模拟对象的装饰器--函数装饰器【重点中的重点】
Python中被装饰后的函数,函数名等函数属性会发生改变(相当于另一个函数了),所以,Python的functools包中提供了一个叫wraps的装饰器来解决该问题。它能使其保留原有函数的结构。
1、不加@wraps()的装饰器:
import time
class MyLog(object):
def __call__(self, func):
def my_log(*args, **kwargs):
"""这里是my_log的docstring"""
start = time.time()
res = func(*args, **kwargs)
end = time.time()
print('|传入的原函数的运行时长:{:.4f}'.format(end - start))
return res
return my_log
@MyLog()
def is_test():
"""这里是is_test的docstring"""
print("一个测试方法")
is_test()
print("__name__: ", is_test.__name__)
print("__doc__: ", is_test.__doc__)
运行结果:
看运行结果,会发现,被装饰器装饰后的函数,name和docstring都发生了变化,因为相当于调用my_log函数。
2、加了@wraps()的装饰器
import time
from functools import wraps
class MyLog(object):
def __call__(self, func):
@wraps(func)
def my_log(*args, **kwargs):
"""这里是my_log的docstring"""
start = time.time()
res = func(*args, **kwargs)
end = time.time()
print('|传入的原函数的运行时长:{:.4f}'.format(end - start))
return res
return my_log
@MyLog()
def is_test():
"""这里是is_test的docstring"""
print("一个测试方法")
is_test()
print("__name__: ", is_test.__name__)
print("__doc__: ", is_test.__doc__)
运行结果 :
看运行结果,会发现,装饰器加了@wraps后,被装饰器装饰后的函数,还是保持原有的状态
1、装饰器的作用: 在不改变原有功能代码的基础上, 添加额外的功能。
2、@wraps(func)的作用: 不改变使用装饰器原有函数的结构(如name, doc)。