【问题标题】:multiple python decorators多个python装饰器
【发布时间】:2013-06-15 23:48:39
【问题描述】:

我有一个带有修饰方法 (my_method) 的 Django 模型 (MyModel)。 我希望装饰器对 my_method 进行一些检查:

  • 如果检查成功,my_method 应该返回一个字符串;

  • 如果检查不成功,my_method 应该返回装饰器返回的失败消息。

逻辑如下:

# models.py
class MyModel(models.Model):
    @decorator1
    @decorator2
    def my_method(self, request, *args, **kwargs):
        return u'The result that must be returned if all the checks performed by the decorator succeed'


# decorators.py
from functools import wraps

# decorator1 checks if certain conditions are met. If yes, it returns the decorated method (method_to_decorate); if not, it returns a tuple
def decorator1(method_to_decorate):
    @wraps(method_to_decorate)
    def wrapper1(self, request, *args, **kwargs):
        if a_condition :
            return method_to_decorate(self, request, *args, **kwargs)
        else:
            # we return a failure message
            return ('failure', 'message') 
    return wrapper1

# in decorator2, we want to know if the check performed by decorator1 was successful
# in case of success, we perform decorator2's check
# in case of failure, decorator2 should simply pass the failure message returned by decorator1   
def decorator2(method_to_decorate):
    @wraps(method_to_decorate)
    def wrapper2(self, request, *args, **kwargs):

        # if the first decorator succeeded
        if decorator1_s_test_was_successful:
            # we check if the conditions of the second decorator are met
            if decorator2_s_test_was_successful:
                # we return the method
                return method_to_decorate(self, request, *args, **kwargs)
            else:
                # we return a failure message
                return ('another failure', 'message')
    # if the first decorator did not succeed
        else: # decorator1 returned a tuple : ('failure', 'message') 
            return the_failure_that_decorator1_returned  
    return wrapper2

所以,如果 decorator1 返回失败,我希望 an_instance_of_my_model_instance.my_method(request) 返回 ('failure', 'message')。如果 decorator1 成功但不是 decorator2,我会期望('另一个失败','消息')。并且如果所有的测试都通过了,u'装饰器执行的所有检查都成功时必须返回的结果'

如果 decorator1 的检查成功通过,我不知道如何检查 decorator2。我试图通过检查 decorator2 中 method_to_decorate 的 type() 来做到这一点,但似乎 type 使用的是原始方法本身,而不是 decorator1 返回的结果(好像装饰器不知道以前的装饰器执行的操作) .

提前谢谢你!

【问题讨论】:

    标签: python decorator python-decorators


    【解决方案1】:

    如果您希望 decorator2 检查 decorator1 返回的任何内容,则需要交换 @decorator1@decorator2 行:

    @decorator2
    @decorator1
    def my_method(self, request, *args, **kwargs):
        return u'The result that must be returned if all the checks performed by the decorator succeed'
    

    现在decorator2 将包装decorator1 返回的任何方法,因此您可以检查该方法返回的内容。

    def decorator2(method_to_decorate):
        @wraps(method_to_decorate)
        def wrapper2(self, request, *args, **kwargs):
    
            result = method_to_decorate(self, request, *args, **kwargs)
    
            if isinstance(result, tuple) and result and result[0] == 'failure':
                # decorator1 returned a failure
                return result
            else:
                # decorator1 passed through the wrapped method call
                if decorator2_s_test_was_successful:
                    return result
                else:
                    return ('another failure', 'message')
    
        return wrapper2
    

    【讨论】:

    • 好的,谢谢 Martijn,这行得通。我害怕颠倒装饰器的顺序,但它可以解决问题。
    【解决方案2】:

    装饰器将按照您将它们放在装饰方法之上的顺序调用,并且根据您的程序结构,如果decorator1 失败,则不会调用decorator2,因此无需检查decorator1 是否被调用在decorator2成功。

    一个稍微简单的例子……

    from functools import wraps
    
    
    def decorator1(f):
        @wraps(f)
        def wrapper(a):
            if a >= 1:
                return f(a)
            return 'failed in decorator 1'
        return wrapper
    
    def decorator2(f):
        @wraps(f)
        def wrapper(a):
            if a >= 2:
                return f(a)
            return 'failed in decorator 2'
        return wrapper
    
    @decorator1
    @decorator2
    def my_func(a):
        return 'success'
    
    
    print my_func(0)
    print my_func(1)
    print my_func(2)
    

    ...打印...

    failed in decorator 1
    failed in decorator 2
    success
    

    【讨论】:

      猜你喜欢
      • 2015-02-22
      • 2016-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-16
      • 1970-01-01
      • 1970-01-01
      • 2016-07-26
      相关资源
      最近更新 更多