Python装饰器及functools模块

装饰器是一个函数,其主要用途是包装另一个函数或类。这种包装的目的是透明地修改或增强被包装对象的形为。表示装饰器的特殊符号是@,

@trace
def square(x):
    return x * x

等价于

def square(x):
    return x * x
square = trace(square)

示例:

1 对带参数的函数进行装饰

def deco(func):
    def _deco(a, b):
        print("before myfunc() called.")
        ret = func(a, b)
        print("after myfunc() called. result: %s" % ret)
        return ret
    return _deco
 
@deco
def myfunc(a, b):
    print(" myfunc(%s,%s) called." % (a, b))
    return a + b
 
myfunc(1, 2)
更加通用的函数装饰器

def logpath(func):
    def with_logging(*args, **kwargs):
        print "Entering %s.%s" % (args[0].__class__.__name__, func.__name__)
        return func(*args, **kwargs)
    return with_logging


class Test:
    @logpath
    def function_one(self):
        pass
    @logpath
    def function_two(self, a, b):
        pass

Test().function_one()
Test().function_two(1, 2)

2 带参数的装饰器

def deco(arg):
    def _deco(func):
        def __deco():
            print("before %s called [%s]." % (func.__name__, arg))
            func()
            print("  after %s called [%s]." % (func.__name__, arg))
        return __deco
    return _deco
 
@deco("mymodule")
def myfunc():
    print(" myfunc() called.")

实际上, deco("mymodule")的返回值为_deco, @_deco是一个函数装饰器

一个有趣的应用如下:

class locker:
    def __init__(self):
        print("locker.__init__() should be not called.")
         
    @staticmethod
    def acquire():
        print("locker.acquire() called.")
         
    @staticmethod
    def release():
        print("  locker.release() called.")
 
def deco(cls):
    def _deco(func):
        def __deco():
            print("before %s called [%s]." % (func.__name__, cls))
            cls.acquire()
            try:
                return func()
            finally:
                cls.release()
        return __deco
    return _deco
 
@deco(locker)
def myfunc():
    print(" myfunc() called.")
 
myfunc()


functools模块wraps装饰器

这是一个很有用的装饰器。函数是有几个特殊属性比如函数名,在被装饰后,会变成包装函数的属性。

例如

from functools import wraps
def logpath(func):
    #@wraps(func)
    def with_logging(*args, **kwargs):
        print "Entering %s.%s" % (args[0].__class__.__name__, func.__name__)
        return func(*args, **kwargs)
    return with_logging


class Test:
    @logpath
    def function_one(self):
        pass
    
    @logpath
    def function_two(self, a, b):
        pass

Test().function_one()
Test().function_two(1, 2)

print Test().function_one.__name__ #with_logging
print Test().function_two.__name__ #with_logging

然而:

from functools import wraps
def logpath(func):
    @wraps(func)
    def with_logging(*args, **kwargs):
        print "Entering %s.%s" % (args[0].__class__.__name__, func.__name__)
        return func(*args, **kwargs)
    return with_logging


class Test:
    @logpath
    def function_one(self):
        pass
    
    @logpath
    def function_two(self, a, b):
        pass

Test().function_one()
Test().function_two(1, 2)

print Test().function_one.__name__ #function_one
print Test().function_two.__name__ #function_two


参考文献:

1, http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html

2, http://stackoverflow.com/questions/308999/what-does-functools-wraps-do


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值