Python decorator

1) Definition
Decorator is actually a function, or more strictly is a callable. It acts like the "decorator" design pattern in a sense.

2)  How to define a decorator and how to call the decorator
@decorator(decorator_opt_args)
def func2be_decorated(func_opt_args)
    ...
For eg:
@dec
def func(arg1, ...):
    ...
The above "decorator" equals something like this: func = dec(func). So when we invoke func('abc'), what is actually doing is "dec(func)('abc')".
To be more elaborate:
def a_decorator(func):   #<<<<< Take the original "func" as the parameter.
    def new_func(*args, **argkw):
        print 'in new_func'
        return func(*args, **argkw)
    print 'in a_decorator'
    return new_func         # <<<  Return a new wrapper func, which usually takes the same args as the original one
@a_decorator
def f(args):   # At this very point, a_decorator is executed ('in a decorator' will be printed), 
    print 'in f'   # and "f" is rebound to "new_func" returned by a_decorator
    print args
print type(f), f.__name__  # prints "<type 'function'> new_func"
How it works ?
a) @a_decorator ... is actually an immediate function call with "f" as the parameter.
     "a_decorator" is executed immediately when the interpreter sees this definition (@a_decorator def f...).
b) After calling a_decorator, the "new_func" is returned, which will rebind this returned new function to "f" just like f = new_func.
c) If we have followed calls to "f", we are actually calling "new_func".

Note, the "a_decorator(f)" in the following explanation has already been executed when the interpreter sees the decorator definition.
f('abc') => a_decorator(f)('abc')  =>  new_func('abc')  # a_decorator(f) returns "new_func" => output: 'in new func' and then 'in f' and then 'abc'

What if decorator itself takes arguments ?
def a_decorator2(dec_args):   #<<<<< decorator itself takes args.
    def _a_nested_one(func):  # <<<<< this nested one takes the original func as the parameter
        print 'in _a_nested_one'
        def new_func(*args, **argkw):
            print 'in new_func'
            return func(*args, **argkw)
        return new_func  # <<<<< this nested one returns new wrapper func  which usually
    print dec_args         #  takes the same args as the original one
    return _a_nested_one    # <<<  Return a nested decorator, which usually takes original func as the parameter

@a_decorator2('hello')  # <<<<< We need provide parameters here, what if we miss the parameter ? 
def ff(args):    # At this very point, a_decorator2 and _a_nested_one have been executed, 
    print 'in ff'    # and "ff" is rebound to "new_func". So, it prints "hello" and "in _a_nested_one".
    print args

First when Python interpreter encounters "@a_decorator2('hello')", it invokes a_decorator2('hello') immediately which prints "hello" and returns a nested decorator "a_nested_one" and the nested decorator is also called immediately, so "in _a_nested_one" is printed.

3) object as a decorator
The object must be callable which means it must defines the __call__() method

class EntryExit(object):
    def __init__(self, f):
         print "init EntryExit"
        self._f = f
    def __call__(self, *args, **argkw):
        print 'Entering %s' %self._f.__name__
        self._f(*args, **argkw)
        print 'Exited %s' %self._f.__name__
@EntryExit  
def func1(s):  # At this point, EntryExit.__init__ has been called and func1 is rebound to an EntryExit instance
    print 'inside func1() - %s' %s

print type(func1)  # <class '__main__.EntryExit'>
func1('hello')
Equivalent function decorator version
def entry_exit(f):
    def new_f(*args, **argkw):
        print 'Entering %s' %f.__name__
        f(*args, **argkw)
        print 'Exited %s' %f.__name__
    new_f.__name__ = f.__name__
    return new_f


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值