Python,Tornado:gen.coroutine decorator破坏了另一个decorator

Python,Tornado:gen.coroutine decorator破坏了另一个decorator,python,exception,tornado,decorator,Python,Exception,Tornado,Decorator,我有一个类,有很多静态方法和Tornado协同程序装饰器。我想添加另一个decorator,以捕获异常并将其写入文件: # my decorator def lifesaver(func): def silenceit(*args, **kwargs): try: return func(*args, **kwargs) except Exception as ex: # collect info and f

我有一个类,有很多静态方法和Tornado协同程序装饰器。我想添加另一个decorator,以捕获异常并将其写入文件:

# my decorator
def lifesaver(func):
    def silenceit(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except Exception as ex:
            # collect info and format it
            res = ' ... '
            # writelog(res)
            print(res)
            return None

    return silenceit
但是,它不适用于
gen.coroutine
decorator:

class SomeClass:

    # This doesn't work!
    # I tried to pass decorators in different orders,
    # but got no result.
    @staticmethod
    @lifesaver
    @gen.coroutine
    @lifesaver
    def dosomething1():
        raise Exception("Test error!")


    # My decorator works well
    # if it is used without gen.coroutine.
    @staticmethod
    @gen.coroutine
    def dosomething2():
        SomeClass.dosomething3()

    @staticmethod
    @lifesaver
    def dosomething3():
        raise Exception("Test error!")
我知道,Tornado使用了
提高回报(…)
的方法,这可能是基于异常的,也许它会以某种方式阻止其他装饰程序的尝试捕获。。。那么,我如何使用我的装饰器来处理Tornado协同程序的异常呢

答案 多亏了Martijn Pieters,我的代码得以运行:

def lifesaver(func):
    def silenceit(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except (gen.Return, StopIteration):
            raise
        except Exception as ex:
            # collect info and format it
            res = ' ... '
            # writelog(res)
            print(res)

            raise gen.Return(b"")

    return silenceit

所以,我只需要指定Tornado
Return
。我试图将
@gen.coroutine
装饰器添加到
沉默
函数中,并在其中使用
屈服
,但这会导致
未来
对象的
未来
对象和其他一些奇怪的不可预测行为。

您正在装饰
gen.coroutine
的输出,因为装饰器是从下到上应用的(因为它们是从上到下相互嵌套的)

与其装饰协同程序,不如装饰您的函数,并将
gen.coroutine
装饰器应用于该结果:

@gen.coroutine
@lifesaver
def dosomething1():
    raise Exception("Test error!")
您的装饰程序无法真正处理
@gen.coroutine
装饰函数生成的输出。Tornado依赖异常来传递结果(因为在Python 2中,生成器不能使用
return
来返回结果)。你需要确保通过龙卷风所依赖的例外情况。您还应该重新包装包装器函数:

from tornado import gen

def lifesaver(func):
    @gen.coroutine
    def silenceit(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except (gen.Return, StopIteration):
            raise
        except Exception as ex:
            # collect info and format it
            res = ' ... '
            # writelog(res)
            print(res)
            raise gen.Return(b"")

    return silenceit
在异常情况下,将引发一个空的
Return()
对象;根据需要进行调整


帮你自己一个忙,不要使用类,只要把
staticmethod
函数放在里面就行了。只需将这些功能放在模块的顶层即可。类用于组合方法和共享状态,而不是创建名称空间。使用模块来创建名称空间。

您正在装饰
gen.coroutine
的输出,因为装饰器是从下到上应用的(因为它们是从上到下嵌套的)

与其装饰协同程序,不如装饰您的函数,并将
gen.coroutine
装饰器应用于该结果:

@gen.coroutine
@lifesaver
def dosomething1():
    raise Exception("Test error!")
您的装饰程序无法真正处理
@gen.coroutine
装饰函数生成的输出。Tornado依赖异常来传递结果(因为在Python 2中,生成器不能使用
return
来返回结果)。你需要确保通过龙卷风所依赖的例外情况。您还应该重新包装包装器函数:

from tornado import gen

def lifesaver(func):
    @gen.coroutine
    def silenceit(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except (gen.Return, StopIteration):
            raise
        except Exception as ex:
            # collect info and format it
            res = ' ... '
            # writelog(res)
            print(res)
            raise gen.Return(b"")

    return silenceit
在异常情况下,将引发一个空的
Return()
对象;根据需要进行调整


帮你自己一个忙,不要使用类,只要把
staticmethod
函数放在里面就行了。只需将这些功能放在模块的顶层即可。类用于组合方法和共享状态,而不是创建名称空间。使用模块来创建名称空间。

谢谢您的回复!我在Q中提到,我尝试了不同的装饰程序顺序,甚至
@lifesaver@gen.coroutine@lifesaver
,但这仍然不起作用,请求返回500:内部服务器错误。@AivanF.:对,因为
gen.coroutine
总是需要一个生成器。我刚看了文档。我明白了,非常感谢!我将尝试声明函数,而不是静态方法
:)
@AivanF:我更新了我的答案,以更好地反映Tornado实现的实际情况。正如您所示,我尝试使用协程装饰器和
屈服
,但遇到了很多麻烦。但是,您使用的
gen.Return
足以解决此问题。请参阅我的问题更新。谢谢您的回复!我在Q中提到,我尝试了不同的装饰程序顺序,甚至
@lifesaver@gen.coroutine@lifesaver
,但这仍然不起作用,请求返回500:内部服务器错误。@AivanF.:对,因为
gen.coroutine
总是需要一个生成器。我刚看了文档。我明白了,非常感谢!我将尝试声明函数,而不是静态方法
:)
@AivanF:我更新了我的答案,以更好地反映Tornado实现的实际情况。正如您所示,我尝试使用协程装饰器和
屈服
,但遇到了很多麻烦。但是,您使用的
gen.Return
足以解决此问题。请参阅我的问题更新。