Java 程序猿学 python:装饰器

内容纲要

我用 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 的注解来理解,那么就有理解不了的地方了

  1. 注解本身引用了一个变量 scheduler
  2. 注解本身貌似还在调用变量 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 装饰器是装饰模式

代理模式和装饰模式的区别在哪?

  1. 装饰模式无论如何都会执行被装饰的方法;而代理模式不同,被代理的方法不一定会被执行
  2. 装饰模式除了执行被装饰的方法,总会额外执行一些功能;代理模式如果执行被代理的方法,并不一定会执行额外的动作
Java 程序猿学 python:装饰器

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

Scroll to top
粤ICP备2020114259号 粤公网安备44030402004258