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

这是重要文档

像上面处理这就对了

posted @   Doctor_Bool  阅读(180)  评论(0编辑  收藏  举报
编辑推荐:
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
阅读排行:
· 开发者新选择:用DeepSeek实现Cursor级智能编程的免费方案
· Tinyfox 发生重大改版
· 独立开发经验谈:如何通过 Docker 让潜在客户快速体验你的系统
· 小米CR6606,CR6608,CR6609 启用SSH和刷入OpenWRT 23.05.5
· 近期最值得关注的AI技术报告与Agent综述!
点击右上角即可分享
微信分享提示