简体   繁体   中英

Raise exception or return gen.Return object in Tornado coroutine

We have a Python 2 project where we actively use coroutines. We can't find any guidelines on exceptions handling inside coroutines.

For example, here lead developer of Tornado mentioned that coroutines should never raise an exception , but it is not clear why. Looks like this approach works and heavily used in Tornado.web itself:

https://github.com/tornadoweb/tornado/blob/master/demos/blog/blog.py#L180

class AuthCreateHandler(BaseHandler):
    def get(self):
        self.render("create_author.html")

    @gen.coroutine
    def post(self):
        if self.any_author_exists():
            raise tornado.web.HTTPError(400, "author already created")
        hashed_password = yield executor.submit(
            bcrypt.hashpw, tornado.escape.utf8(self.get_argument("password")),
            bcrypt.gensalt())

tornado.web.HTTPError just extends base Exception class. Also, discussion here https://github.com/tornadoweb/tornado/issues/759#issuecomment-91817197 suggests that raising exception inside coroutine is appropriate.

Also here , active Tornado contributor suggests that raising exceptions is fine:

class PostHandler(tornado.web.RequestHandler):
    @gen.coroutine
    def get(self, slug):
        post = yield db.posts.find_one({'slug': slug})
        if not post:
            raise tornado.web.HTTPError(404)

        self.render('post.html', post=post)

Is there any downsides to raising exceptions inside Tornado coroutines or should we raise gen.Return(exception_object) ?

In Python 2, only use raise gen.Return(value) to return a normal value, not to raise an exception. It is exactly the equivalent of return value in a coroutine in Python 3.

To raise an exception from a coroutine, a normal raise Exception() is correct. The wonderful thing about coroutines is their exception-handling semantics are pretty much the same as regular functions.

Raising exceptions inside coroutines is perfectly normal. When I said "coroutines should never raise an exception" I was referring to what happens when you call a coroutine without yield or await : The exception is captured and held until the coroutine's return value is either yielded or awaited .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM