为什么不能在定义之间链接Python装饰器? [英] Why can't Python decorators be chained across definitions?

查看:75
本文介绍了为什么不能在定义之间链接Python装饰器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下两个脚本为什么不等效?

Why arn't the following two scripts equivalent?

(来自另一个问题:了解Python装饰器

def makebold(fn):
    def wrapped():
        return "<b>" + fn() + "</b>"
    return wrapped

def makeitalic(fn):
    def wrapped():
        return "<i>" + fn() + "</i>"
    return wrapped

@makebold
@makeitalic
def hello():
    return "hello world"

print hello() ## returns <b><i>hello world</i></b>

并带有装饰性装饰器:

def makebold(fn):
    def wrapped():
        return "<b>" + fn() + "</b>"
    return wrapped

@makebold
def makeitalic(fn):
    def wrapped():
        return "<i>" + fn() + "</i>"
    return wrapped

@makeitalic
def hello():
    return "hello world"

print hello() ## TypeError: wrapped() takes no arguments (1 given)

我为什么想知道?我已经编写了一个 retry 装饰器来捕获MySQLdb异常-如果该异常是短暂的(例如Timeout),它将在睡眠一小会后重新调用该函数。

Why do I want to know? I've written a retry decorator to catch MySQLdb exceptions - if the exception is transient (e.g. Timeout) it will re-call the function after sleeping a bit.

我还有一个 modifys_db 装饰器,用于处理一些与缓存有关的内务处理。 modify_db retry 装饰,所以我假设所有用 modify_db 也会隐式重试。我在哪里出错了?

I've also got a modifies_db decorator which takes care of some cache-related housekeeping. modifies_db is decorated with retry, so I assumed that all functions decorated with modifies_db would also retry implicitly. Where did I go wrong?

推荐答案

第二个示例的问题是

@makebold
def makeitalic(fn):
    def wrapped():
        return "<i>" + fn() + "</i>"
    return wrapped

试图装饰 makeitalic ,装饰器,而不是包装的,它返回的函数。

is trying to decorate makeitalic, the decorator, and not wrapped, the function it returns.

您可以按照我的想法做您打算使用这样的东西:

You can do what I think you intend with something like this:

def makeitalic(fn):
    @makebold
    def wrapped():
        return "<i>" + fn() + "</i>"
    return wrapped

此处 makeitalic 使用 makebold 装饰包裹的

这篇关于为什么不能在定义之间链接Python装饰器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆