内容纲要
我用 python 做了个自动签到的小程序,用到了 APScheduler 来调度签到机器人每天凌晨自动登录并签到。其中有这么一段代码
...
scheduler = BlockingScheduler()
@scheduler.scheduled_job('cron', day='*', hour='0', minute='30', second='0')
def smzdm_sign():
logging.info('smzdm sign...')
smzdm = SmzdmRobot('******', '******')
smzdm.sign()
...
作为一个 java 程序猿,对 @scheduler.scheduled_job('cron', day='*', hour='0', minute='30', second='0')
并不陌生,这不就是注解嘛,但是好像有点什么不对
是滴,如果用 java 的注解来理解,那么就有理解不了的地方了
- 注解本身引用了一个变量
scheduler
- 注解本身貌似还在调用变量
scheduler
的方法cheduled_jon()
java 的注解可没有这样用的,所以这里不能用 java 的注解来解释。
这里实际上是 python 的装饰器,具体的说,是一个带参数的装饰器。这个注解的效果如果用 python 代码写出来应该是
smzdm_sign = scheduler.scheduled_job('cron', day='*', hour='0', minute='30', second='0')(smzdm_sign)
或者更容易理解的代码
# func 是一个函数
func = scheduler.scheduled_job('cron', day='*', hour='0', minute='30', second='0')
# 现在 smzdm_sign 指向了 func(smzdm_sign) 的返回值 new_func,这个返回值也是个函数
# 将来调用 smzdm_sign 实际是在调用 new_func 函数
new_func = func(smzdm_sign)
smzdm_sign = new_func
我们看下 scheduled_job 的源码
def scheduled_job(self, trigger, args=None, kwargs=None, id=None, name=None,
misfire_grace_time=undefined, coalesce=undefined, max_instances=undefined,
next_run_time=undefined, jobstore='default', executor='default',
**trigger_args):
"""
scheduled_job(trigger, args=None, kwargs=None, id=None, \
name=None, misfire_grace_time=undefined, \
coalesce=undefined, max_instances=undefined, \
next_run_time=undefined, jobstore='default', \
executor='default',**trigger_args)
A decorator version of :meth:`add_job`, except that ``replace_existing`` is always
``True``.
.. important:: The ``id`` argument must be given if scheduling a job in a persistent job
store. The scheduler cannot, however, enforce this requirement.
"""
def inner(func):
self.add_job(func, trigger, args, kwargs, id, name, misfire_grace_time, coalesce,
max_instances, next_run_time, jobstore, executor, True, **trigger_args)
return func
return inner
可以看到该方法返回了一个 inner
函数,也就是我们在 更容易理解的代码 里的 func
函数
那么,从 java 程序猿的角度,这有点像使用注解作为织入点的 AOP,被注解的函数在执行时已经不是原来那个函数了,正如 java 里被注解的那个类,在运行时已经不是原来那个类了(已经是原来那个类的代理类)
不过,正如 装饰器 这个名字所表达的,和 java 的 AOP 还是有本质不同的
- JAVA AOP 是代理模式
- python 装饰器是装饰模式
代理模式和装饰模式的区别在哪?
- 装饰模式无论如何都会执行被装饰的方法;而代理模式不同,被代理的方法不一定会被执行
- 装饰模式除了执行被装饰的方法,总会额外执行一些功能;代理模式如果执行被代理的方法,并不一定会执行额外的动作
Java 程序猿学 python:装饰器