本篇文章简单介绍python装饰器的应用。 若多个不同的函数需要实现一个相同的功能,则可以考虑使用装饰器来实现,而不需要去修改每一个函数。
情景描述1
有一个函数,存在一定概率会运行失败。
|
|
|
|
Fail
---------------------------------------------------------------------------
Exception Traceback (most recent call last)
<ipython-input-4-f3c46ba59b44> in <module>()
----> 1 prob_fail()
<ipython-input-3-6bdb0df19324> in prob_fail()
5 else:
6 print('Fail')
----> 7 raise Exception
Exception:
|
|
Succeed
希望能达到的效果是,在函数运行失败时自动重试。
不用装饰器也可实现
|
|
Fail
Retrying.
Fail
Retrying.
Fail
Retrying.
Fail
Retrying.
Fail
Retrying.
Fail
Retrying.
Succeed
若多个函数都想实现此功能,用装饰器更方便
装饰器的特征:
- Closure 闭包函数
- 外层函数的参数只有一个,且是需要被装饰的函数
|
|
之后只要直接调用函数本身即可。
|
|
Fail
Retrying.
Fail
Retrying.
Fail
Retrying.
Fail
Retrying.
Fail
Retrying.
Fail
Retrying.
Fail
Retrying.
Fail
Retrying.
Fail
Retrying.
Fail
Retrying.
Fail
Retrying.
Succeed
若函数本身有参数,则需要在inner函数中补齐参数设置,以满足不同函数的调用需求
|
|
若想要在装饰器中增加别的参数以实现更多控制,则需要再包一层函数
此处设置了最大重试次数(max_retry_n)和重试等待时间(retry_wait_arg)的控制。
若超过最大重试次数,则抛出MaxRetryNumError,这是Exception类的一个子类。
|
|
|
|
|
|
Fail
Wait 0 seconds before retrying.
Retry Time 1
Fail
Wait 3 seconds before retrying.
Retry Time 2
Fail
Wait 12 seconds before retrying.
Retry Time 3
Fail
Wait 27 seconds before retrying.
---------------------------------------------------------------------------
MaxRetryNumError Traceback (most recent call last)
<ipython-input-18-f3c46ba59b44> in <module>()
----> 1 prob_fail()
<ipython-input-15-b95d7b9d96bc> in inner(*args, **kargs)
18 i += 1
19 if i > max_retry_n:
---> 20 raise MaxRetryNumError('Reach the Max Retry Number: {}! '.format(max_retry_n))
21 print('Retry Time {}'.format(i))
22
MaxRetryNumError: Reach the Max Retry Number: 3!
情景描述2(修改于2017-05-17)
现在有一堆函数,都是输入一个dataframe,输出一个dataframe。 现在为了运用既定的流程,并且保留dataframe的读取path,我希望所有的函数都能接收一个path和一个dataframe,输出也是path和dataframe。
原函数定义
用简单函数来做演示,func1
的功能是给输入的数字加上2
。
12def func1(x): return x+2
运行效果如下:
1func1(2)
4
定义装饰器
|
|
应用装饰器
装饰器定义好后,在每个原函数定义前加上@decorator
。
123def func1(x): return x+2
这样再调用func1
时,func1
的参数就从一个变成了两个,输出也相应地改变了。
1func1('x', 1)
('x', 3)
总结
装饰器decorator
本身是一个函数,同时,它的输入参数必须是一个函数,就是需要被装饰的原函数func
,它的输出return
也是一个函数inner
。inner
负责调用原函数func
,及进行相应的改造。