Python,Tornado:gen.coroutine decorator破坏了另一个decorator
我有一个类,有很多静态方法和Tornado协同程序装饰器。我想添加另一个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
# 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
足以解决此问题。请参阅我的问题更新。