【问题标题】:Decorator after @task decorator in celerycelery 中 @task 装饰器之后的装饰器
【发布时间】:2013-10-24 04:43:47
【问题描述】:

我正在尝试在 celery @task 装饰器之后应用一个装饰器,类似于。

@send_email
@task
def any_function():

   print "inside the function"

我可以让它按照文档中推荐的方式工作,即将装饰器放在任务装饰器之前,但在这种情况下,我想在我的装饰器中访问任务实例。

@send_email 必须是类装饰器,这是我尝试但没有成功的方法:

class send_email(object):
    ''' wraps a Task celery class '''
    def __init__(self, obj):

        self.wrapped_obj = obj

        functools.update_wrapper(self, obj)

    def __call__(self, *args, **kwargs):

        print "call"

        return self.wrapped_obj.__call__(*args, **kwargs)

    def run(self, *args, **kwargs):

        print "run"

        return self.wrapped_obj.__call__(*args, **kwargs)

    def __getattr__(self, attr):

        if attr in self.__dict__:

            return getattr(self, attr)

        return getattr(self.wrapped_obj, attr)

我永远无法让 call 或 run 函数中的 print 语句出现在 worker 或 caller 中。

我们如何装饰一个 celery 任务,而不求助于基于类的任务定义(所以装饰器将在函数定义之上的@task 之上。

感谢您的帮助!

米格尔

【问题讨论】:

    标签: python celery decorator django-celery


    【解决方案1】:

    任务装饰器不返回一个类,它返回一个实例。

    看来您的问题应该是“我如何才能访问装饰器内部的任务”,而不是如何先应用装饰器。

    在即将发布的 3.1(开发版)中,您可以使用绑定任务来完成此操作:

    def send_email(fun):
        @wraps(fun)
        def outer(self, *args, **kwargs):
            print('decorated and task is {0!r}'.format(self))
            return fun(self, *args, **kwargs)
    
        return outer
    
    @task(bind=True)
    @send_email
    def any_function(self):
        print('inside the function')
    

    对于以前的版本,您可以使用current_task

    from celery import current_task
    
    def send_email(fun):
    
        @wraps(fun)
        def outer(*args, **kwargs):
            print('decorated and task is: %r' % (current_task, ))
            return fun(*args, **kwargs)
    
        return outer
    
    @task
    @send_email
    def any_function():
        print('inside the function')
    

    【讨论】:

    • 谁能解释一下 {0!r} 在做什么?经过一段时间的搜索,我在 Python 文档中找到了这个:'!r' (apply repr()) 可用于在格式化之前转换值。但是 repr() 所做的定义似乎很模糊。谢谢,
    • @AnthonyRoberts 所有对象都有两种不同的呈现方式[1]:str(obj)(它调用obj.__str__())通常用于在用户界面中显示等等,然后是@987654326 @(调用obj.__repr__())用于调试目的,经常打印对象的类型、对象的内存位置和重要属性。在格式字符串中,"{0!s}" 是前者,"{0!r}" 是后者,在旧格式中它们分别是 "%s""%r"。 [1]:Python2中有三个:__unicode____str____repr__
    • 我陷入了一个稍微不同的境地。考虑到这个问题,如果我想在any_function 的开头和结尾做一些数据库操作。此外,我希望能够在any_function 出现异常时执行另一个数据库操作。我该怎么办?
    【解决方案2】:

    “之前”在视觉上看起来像“之后”。

    例如,这个:

    @decorator1
    @decorator2
    @decorator3
    def func():
      pass
    

    相当于:

    def func():
      pass
    
    func = decorator1(decorator2(decorator3(func)))
    

    这意味着您必须在@task 之后写@send_email 才能在@task 之前应用它。例如:

    @task
    @send_email
    def any_function():
        print "inside the function"
    

    【讨论】:

    • 我希望它在@task之后应用,问题是\@task返回一个类
    猜你喜欢
    • 2016-07-26
    • 1970-01-01
    • 1970-01-01
    • 2011-09-03
    • 2015-11-18
    • 1970-01-01
    • 1970-01-01
    • 2015-02-01
    • 2020-01-02
    相关资源
    最近更新 更多