python装饰器终极奥义

python装饰器终极奥义

python装饰器

定义:本质是函数,(装饰其他函数)就是为其他函数添加附加功能
原则:
1. 不能修改被装饰的函数的源码
2. 不能修改原函数的调用方式
知识储备: 1. 函数即变量 函数执行的时候解释器从上向下执行 2. 高阶函数
a. 把一个函数名当作实参传递给另一个函数(可以做到在不修改函数源码的情况下,为其添加功能) b. 返回值中包含函数名 3. 嵌套函数
当装饰器需要参数需要三层嵌套,不需要参数两层嵌套

装饰器可能的应用

作为一个函数

创造装饰器最简单的方法就是写一个函数,返回包装原始函数调用的一个子函数

def mydecorator(function):  
    def wrapped(*args,**kwargs):  
        #调用原始函数之前做的操作  
        result=function(*args,**kwargs)  
        #调用原始函数之后做点什么  
        #返回结果  
        return result  
    #返回wrapper作为装饰函数  
    return wrapped

作为一个类

大多数情况装饰器总是用函数实现,但在某些情况下使用类会更好。如果装饰器需要复杂的参数化或者依赖特定状态,就会使用装饰类
通用模式

class DecoratorAsClass:  
def __init__(self,function):
self.function=function
def __call__(self,*args,**kwargs):
#在调用原始函数指点,做点什么
result=self.function(*args,**kwargs)
#在调用原始函数之后做点什么
#返回函数执行结果
return result
@DecoratorAsClass
def hello():
print('hello')
hello()

参数化装饰器

实际使用装饰器需要使用参数化的装饰器。类装饰器不用说,初始化的时候就可以传入参数。如果是函数作装饰器的话,就需要第二层包装。如需要多次执行一个原始函数,而重复次数通过装饰器参数给定,下面是示例代码

def repeat(number=3):  
"""多此执行装饰函数,返回最后一次执行结果
参数名为 number:重复次数,默认为3
"""
def erceng_decorator(function):
def wrapper(*args,**kwargs):
result=None
for _ in range(number):
result=function(*args,**kwargs)
return result
return ercent_decorator
@repeat(2)
def hello():
print("hello")
hello()
hello
hello

在使用参数化装饰器的时候参数有默认值,但名字后面必须加括号,否则会报错

保存内省的装饰器

在使用装饰器常见的问题就是无法保存原始函数的元数据(文档字符串和函数名),装饰器组合创建了一个新的函数,返回一个新的对象,但没有考虑到原始函数的标识。这回给调试造成麻烦,无法找寻原始函数,也会破坏自动生成文档的工具,无法访问原始函数的文档字符串

def dummy_dec(function):
... def wrapped(*args,**kwargs):
... """包装函数内部文档。"""
... return wrapped
@dummy_dec
... def function_important_doc():
... """这是重要文档"""
function_important_doc.__name__
'wrapped'
>>> function_important_doc.__doc__
'包装函数内部文档。'

如上所示,原始函数的名字和文档都被修改了,解决这个问题也很容易,使用functools模块内置的wraps()装饰器:

from functools import wraps  
def chuli_dec(function):
@wraps(function)
def wrapper(*args,**kwargs):
"""包装函数文档"""
return function(*args,**kwargs)
return wrapper
@chuli_dec
def func_import_doc():
"""这是重要文档"""
print(func_import_doc.__name__)
print(func_import_doc.__doc__)
func_import_doc
这是重要文档

像上面处理这就对了

原文地址:https://www.cnblogs.com/dcotorbool/p/8158008.html