【Python】Python装饰器

学习笔记

平时用到Python装饰器的地方比较少,最近写一个项目,用到了装饰器。在此把学习过程及要点记录一下。如果你正在熟悉装饰器相关内容,希望它能给到你一些帮助。
参考资料

1. 装饰器是一个特殊的函数

如果我们想在已有的函数的基础上再增加某个功能(装饰一下),那么可以采用如下的方式:

def func(param):
    # do something.

def decorating(specified_func):
    def wrapper(params):
        # before calling func, do something ....
        specified_func(params)
        # after calling func, do something ...
    return wrapper
   
if __name__ == "__main__":
    decorated_func = decorating(func)
    decorated_func(args)

函数decoratingfunc的基础上装饰了某些新功能,形成被装饰的函数对象decorated_func。 除了附加功能外,函数对象decorated_func 调用方式和原来的func完全一样。

python中对此提供了一个语法糖,简化了编程书写形式:

def decorating(specified_func):
    def wrapper(params):
        # before calling func, do something ....
        specified_func(params)
        # after calling func, do something ...
    return wrapper
    
@decorating
def func(param):
    # do something.
    
if __name__ == "__main__":
    func(args)

此时,调用func和上面的例子中调用decorated_func是完全一样的。

2. 带参装饰器

我们在上面的例子中再包装一层,就形成了带参装饰器。如下:

def func(params):
    # do something ...

def decorating_with_param(decorator_params):
    def decorating(specified_func):
        def wrapper(params):
            #before call func, do something with decorator_params...
            specified_func(params)
            #after call func, do something with decorator params ...
        return wrapper
    return decorating

if __name__ == "__main__":
    arg_decorated_func = decorating_with_param(decorator_args)(func)
    arg_decorated_func(args)

同样的, 使用装饰器的书写形式,就变成了:

def decorating_with_param(decorator_params):
    def decorating(specified_func):
        def wrapper(params):
            #before call func, do something with decorator_params...
            specified_func(params)
            #after call func, do something with decorator params ...
        return wrapper
    return decorating
    
@decorating_with_param(decorator_args)
def func(param):
    # do something.
    
if __name__ == "__main__":
    func(args)

此时,调用func和调用arg_decorated_func是完全一样的,仅仅是书写方式不一样而已。

3. 可传递任意参数

为了可以传递任意参数,装饰器的函数参数一般写为如下形式:

def decorating(func):
    def wrapper(*args, **kwargs):
        #before call func, do something here.
        func(*args, **kwargs)
        #after call func, do something ...
    return wrapper

4. 装饰器的修饰顺序

如果有多个装饰器同时修饰一个函数,则离函数最近的装饰器最先应用。例如:

@C
@B
@A
def func(param):
    #do something.

if __name__ == "__main__":
    func(args)

此时调用func的作用等价于:

def func(param):
   # do something..
if __name__ == "__main__":
    dec_a_func = A(func)
    dec_b_func = B(dec_a_func)
    dec_c_func = C(dec_b_func)
    dec_c_func(args)

5. 一个示例

下面这个例子中,func 仅仅休眠指定的时间(s), timeit装饰器打印func开始与结束,并记录单词执行时间,repeate重复执行n次,并记录总时间。

def timeit(func):
    def inner(*args, **kwords):
        print("------begin call {}  -------".format(func))
        t1 = time.time()
        func(*args, **kwords)
        t2 = time.time()
        print("------end {} using %ds.-------".format(func) %(t2-t1))
    return inner

def repeat(iterating):
    def timeit(func):
        def inner(*args, **kwords):
            t1 = time.time()
            for _ in range(iterating):
                func(*args, **kwords)
            t2 = time.time()
            print("iterating %d time(s) using %ds." %(iterating, t2-t1))
        return inner
    return timeit

# @timeit
@repeat(2)
@timeit
def doSomething(n):
    time.sleep(n)

if __name__ == "__main__":
    doSomething(3)

执行结果如下:

joly@ubuntu:~/Workspace/Flask-Learning/4.装饰器$ python3 timeit.py 
------begin call <function doSomething at 0x7f2d589630d0>  -------
------end <function doSomething at 0x7f2d589630d0> using 3s.-------
------begin call <function doSomething at 0x7f2d589630d0>  -------
------end <function doSomething at 0x7f2d589630d0> using 3s.-------
iterating 2 time(s) using 6s.

结束。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值