代码之家  ›  专栏  ›  技术社区  ›  Artem Andreev

python中decorators的不同实现

  •  2
  • Artem Andreev  · 技术社区  · 14 年前

    很抱歉问了这么长的问题,但我不知道怎么把它变短。

    一。不带参数的装饰器

    import time
    import functools
    
    def pause(f):
        @functools.wraps(f)
        def wrapper(*args, **kwargs):
            time.sleep(1)
            return f(*args, **kwargs)
    
        return wrapper
    
    @pause
    def func(x, y):
        """desc"""
        return x + y
    
    print func(1, 2)
    help(func)
    

    输出:

    3
    Help on function func in module __main__:
    
    func(*args, **kwargs)
        desc
    

    它是“经典”实现——很多文章都包含它。

    -必须使用functools来保存函数的名称和doc字符串(问题不大,但代码和魔术稍微多了一点)

    +您可以修改函数参数(并非总是必需的)

    +-? 还有别的吗?

    实施1.2(通过功能)

    import time
    
    def pause(f):
        time.sleep(1)
        return f
    
    @pause
    def func(x, y):
        return x + y
    
    print func(1, 2)
    help(func)
    

    输出:

    3
    Help on function func in module __main__:
    
    func(x, y)
        desc
    

    -不能修改函数参数

    +不中断函数签名

    +更少的代码

    +-? 还有别的吗?

    实施1.3(通过类)

    import time
    
    class pause(object):
        def __init__(self, f):
            self.f = f
    
        def __call__(self, *args, **kwargs):
            time.sleep(1)
            return self.f(*args, **kwargs)
    
    @pause
    def func(x, y):
        """desc"""
        return x + y
    
    print func(1, 2)
    help(func)
    

    输出:

    3
    Help on pause in module __main__ object:
    
    class pause(__builtin__.object)
     |  Methods defined here:
     |  
     |  __call__(self, *args, **kwargs)
     |  
     |  __init__(self, f)
     |  
     |  ----------------------------------------------------------------------
     |  Data descriptors defined here:
     |  
     |  __dict__
     |      dictionary for instance variables (if defined)
     |  
     |  __weakref__
     |      list of weak references to the object (if defined)
    

    嗯,丑八怪。

    实现1.4(通过类)

    import time
    
    class pause(object):
        def __call__(self, f):
            time.sleep(1)
            return f
    
    @pause()
    def func(x, y):
        """desc"""
        return x + y
    
    print func(1, 2)
    help(func)
    

    三
    关于模块中函数func的帮助:
    
    函数(x,y)
    描述
    

    -decorator使用的非标准语法

    +不中断函数签名

    +-代码更少(但多于实现2:)

    2。带args的装饰器

    实施2.1(通过功能)

    import time
    import functools
    
    def pause(t):
        def wrapper(f):
            @functools.wraps(f)
            def tmp(*args, **kwargs):
                time.sleep(t)
                return f(*args, **kwargs)
            return tmp
    
        return wrapper
    
    @pause(1)
    def func(x, y):
        """desc"""
        return x + y
    
    print func(1, 2)
    help(func)
    

    输出:

    三
    
    函数(*args,**kwargs)
    描述
    

    -中断函数签名

    -嵌套比平面差

    +可以修改函数参数

    +-? 还有别的吗?

    实施2.2(通过功能)

    import time
    
    def pause(t):
        def wrapper(f):
            time.sleep(t)
            return f
        return wrapper
    
    @pause(1)
    def func(x, y):
        """desc"""
        return x + y
    
    print func(1, 2)
    help(func)
    

    三
    关于模块中函数func的帮助:
    
    函数(x,y)
    

    ? 为什么it实现很少在文章和示例中使用?我错过了什么?

    -不能修改函数参数

    +不中断函数签名

    +更少的代码

    +-? 还有别的吗?

    实施2.3(通过类)

    import time
    
    class pause(object):
        def __init__(self, darg):
            self.darg = darg
    
        def __call__(self, f):
            time.sleep(self.darg)
            return f
    
    @pause(1)
    def func(x, y):
        """desc"""
        return x + y
    
    print func(1, 2)
    help(func)
    

    三
    关于模块中函数func的帮助:
    
    函数(x,y)
    描述
    

    +不中断函数签名

    +-代码更少(但多于实现2:)

    +-? 还有别的吗?

    一个地方的问题

    1. 为什么实现1.1/2.1在文章和示例中比实现1.2/2.2更常见?
    2. 我还错过了什么吗?
    1 回复  |  直到 14 年前
        1
  •  2
  •   Gintautas Miliauskas    14 年前

    实现1.2&2.2“比”1.1和2.1“不常见”,这当然是好事,因为它们做的事情不同。事实上,我不会称它们为“decorators”,因为它们并没有真正包装(“decorate”)函数。相反,它们只执行一次操作,即解析修饰函数的那一刻。也就是说,它们的操作(在您的情况下是睡眠)是在函数定义时执行的,而不是在函数调用时执行的。

    试着调用你的修饰函数几次,你就会看到不同。