zoukankan      html  css  js  c++  java
  • [TimLinux] Python 再谈装饰器

    参考链接:https://stackoverflow.com/questions/739654/how-to-make-a-chain-of-function-decorators

    1. 函数对象

    • 能够赋值给其他变量
    • 能够在另外函数内定义
    • 能够作为参数进行传递
    • 能够作为函数的返回值
    def firstLevel(f_arg):  # 作为参数,可以赋值
        def tmp_func(*args, **kwargs):   # 可以在另外函数内定义
            # do something ...
            ret = f_arg(*args, **kwargs)
            # do something ...
            return ret
        return tmp_func   # 作为函数的返回值
    
    # 1. 原始方法
    def func(*args, **kwargs):
        print("In func")
    func = firstLevel(func)
    
    # 2. 装饰器方法
    @firstLevel
    def func(*args, **kwargs):
        print("In func")
    
    # 使用
    func()

    2. 多层装饰器

    可以对函数进行一层又一层的包装,使用多层装饰器即可

    def firstLevel(f_arg):
        def tmp_func(*args, **kwargs):
            print("----s.firstLevel----")
            ret = f_arg(*args, **kwargs)
            print("----e.firstLevel----")
            return ret
        return tmp_func
    
    def secondLevel(f_arg):
        def tmp_func(*args, **kwargs):
            print("----s.secondLevel----")
            ret = f_arg(*args, **kwargs)
            print("----e.secondLevel----")
            return ret
        return tmp_func
    
    #1. 原始方法
    def func(*args, **kwargs):
        print("In func")
    func = firstLevel(secondLevel(func))
    func()
    
    # 2. 装饰器方法
    @firstLevel
    @secondLevel 
    def func(*args, **kwargs):
        print("In func")
    func()

    @firstLevel 语法,

    这个后面看似隐藏了一对(),用来将下面的代码作为装饰器函数返回的内部函数的参数进行传递,当明确指定()的时候,则是给装饰器函数传递参数,

    3. 装饰器接收参数

    @firstLevel 语法,告诉我们这个函数接收的参数是一个函数对象,内部返回的是一个函数(firstLevel就是函数名,使用@标记告诉我们的)

    @firstLevel(arg1, arg2, ...) 语法,告诉我们这个firstLevel(arg1, arg2, ...) 函数接收参数,返回的也是一个函数,返回的函数比如叫 retLevel,则将转化为: @retLevel 语法,retLevel 语法就跟上面的语法一样,告诉我们返回的 retLevel 接收的参数是一个函数对象,内部同样返回了一个函数 (retLevel 就是中间函数名,使用@标记告诉我们的)

    def firstLevel(arg1, arg2):
        # do something ...
        print(arg1, arg2)
        # 使用参数做一些事情(这是函数传递参数的目的)
        def tmpRetLevel(f_arg):
            def tmp_func(*args, **kwargs):
                # do something ...
                ret = f_arg(*args, **kwargs)
                # do something ...
                return ret
            return tmp_func
    
        return tmpRetLevel
    
    # 1. 原始方法
    def func(*args, **kwargs):
        print("In func")
    
    retLevel = firstLevel('1', '2')
    func = retLevel(func)
    func('3', '4')
    
    # 2. 装饰器方法
    @firstLevel('1', '2')
    def func(*args, **kwargs):
        print("In func")
    
    func('3', '4')

    4. functools实现装饰器

    上面的返回后的函数,打印一些内部变量比如:func.__doc__, __name__ 将变为 内部函数的 __doc__,__name__ 描述信息,functools.wraps将解决这样的问题,wraps()函数本身就是一个装饰器。

    import functools
    
    
    def firstLevel(f_arg):
        @functools.wraps(f_arg):
        def tmpFunc(*args, **kwargs):
            # do something ...
            ret = f_arg(*args, **kwargs)
            # do something ...
            return ret
        return tmpFunc
    
    @firstLevel
    def func(*args, **kwargs):
        print("In func")
    
    print(func.__name__)  # 输出:func

    4. 使用场景

    • 装饰外部提供的库
    • 避免大量重复代码的编写
    • 比如:Django对视图的权限控制,Twisted将函数修改为异步调用
  • 相关阅读:
    jQuery 2.0.3 源码分析 回调对象
    JQuery+JQuery ui实现的弹出窗口+遮罩层+拖动+更改大小~!
    2019.8.25 小结
    2019.8.23 小结
    宜中食堂游记
    2019.8.21小结
    2019.8.22小结
    2019.8.19小结
    题解 CF499A 【Watching a movie】
    2019.8.18小结
  • 原文地址:https://www.cnblogs.com/timlinux/p/9705064.html
Copyright © 2011-2022 走看看