python decorator是否可以根据先前的decorator结果执行或跳过?

2024-06-01 07:31:35 发布

您现在位置:Python中文网/ 问答频道 /正文

我从这个stack_overflow_entry中了解到,在Python中,修饰符是按照它们在源代码中出现的顺序来应用的。在

那么下面的代码片段应该如何表现呢?在

@unittest.skip("Something no longer supported")
@skipIf(not something_feature_enabled, "Requires extra crunchy cookies to run")
def test_this():
  ....

第一个装饰器(如下所述)要求测试运行程序完全跳过test_this()

^{pr2}$

而第二个修饰符则要求测试运行程序有条件地跳过运行test_this()。在

@skipIf(not something_feature_enabled, "Requires extra crunchy cookies to run")

那么这是否意味着test_this将根本不运行,除非我们将条件跳过修饰符放在第一位?在

另外,在Python中有没有方法定义decorator的依赖执行?e、 g

@skipIf("Something goes wrong")
@skipIf(not something_feature_enabled, "Requires extra crunchy cookies to run")
@log
@send_email
def test_this():
  ....

其思想是在@skipIf("Something goes wrong")true时启用@log和{}的执行。在

抱歉,如果我错过了一些非常明显的东西。在


Tags: toruntestnotenabled修饰符thisextra
1条回答
网友
1楼 · 发布于 2024-06-01 07:31:35

我认为您可能遗漏了一个关键点:decorator只是一个函数,它传递一个函数并返回一个函数。在

所以,这些是相同的:

@log
def test_this():
    pass

def test_this():
    pass
test_this = log(test_this)

同样地:

^{pr2}$

一旦你明白了这一点,你所有的问题都变得相当简单。在


首先,是的,skip(…)被用来修饰skipIf(…)(test),因此如果它跳过它所修饰的内容,test将永远不会被调用。在


定义调用decorator的顺序的方法是按照您希望调用它们的顺序编写它们。在

如果您想动态地这样做,那么首先应该动态地应用decorators。例如:

for deco in sorted_list_of_decorators:
    test = deco(test)

Also, is there any way in Python to define dependent execution of decorators?

不,他们都会被处死。与您的请求更相关的是,每个decorator被应用于decorated函数,而不是decorator。在

但您总是可以将decorator传递给条件decorator:

def decorate_if(cond, deco):
    return deco if cond else lambda f: f

然后:

@skipIf("Something goes wrong")
@decorate_if(something_feature_enabled, log)
@decorate_if(something_feature_enabled, send_email)
def test_this():
    pass

很简单,对吧?在

现在,如果something_feature_enabled是真的,则应用logsend_email修饰符;否则,将应用一个不以任何方式修饰函数而只返回未更改的函数的装饰器。在

但是如果你不能通过decorator,因为函数已经被修饰了呢?好吧,如果您定义每个decorator来公开它包装的函数,那么您总是可以展开它。如果您总是使用functools.wraps(如果您没有其他原因,通常应该这样做,并且即使您有这样的理由,您也可以用这种方式轻松地进行模拟),则包装的函数始终可用作__wrapped__。因此,您可以编写一个decorator,它可以有条件地轻松删除最外层的装饰:

def undecorate_if(cond):
    def decorate(f):
        return f.__unwrapped__ if cond else f
    return decorate

同样,如果你想动态地做这件事,你可能会动态地装饰。因此,一个更简单的解决方案是跳过您不想要的装饰器,在应用它们之前将它们从decositerable中删除。在

相关问题 更多 >