在Python中响应全局对象的异常

时间:2014-02-04 15:35:23

标签: python exception tornado

我是Python的新手,我偶然发现了异常处理的问题。我正在写一个简单的龙卷风+ momoko应用程序。 总之,我有一个在main函数中创建的全局(?)对象,该对象是QueryExecutor类。这是一个使用momoko处理SQ​​L查询执行的简单类。

class QueryExecutor:
    def __init__(self, database):
        self.db = database

    @gen.engine
    def _run(self, query):
        self.db.execute(query, callback = (yield gen.Callback('q')))
        try:
            cursor = yield momoko.WaitOp('q')
        except Exception as error:
            print(str(error))

    def save(self, tablename, data):
        fields = "(" + ", ".join(map(str, list(data.keys()))) + ")"
        values = "(" + "\'" + '\', \''.join(map(str, list(data.values()))) + "\'" + ")"
        query = "INSERT INTO " + tablename + " " + fields + " VALUES " + values + ";"
        self._run(query)

我想要实现的是在请求处理程序中使用此类的对象,并以某种方式能够判断何时发生异常:

class RegistrationHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("templates/register.html")

    def post(self):
        #...handle post arguments, retrieve user data, check if correct etc., do stuff...
        #...if everything ok:
        queryExec.save("users", userdata)
        #what to do if save threw an exception? 


application.db = momoko.Pool(dsn=dbsetup.dsn, size=1)


if __name__ == "__main__":
    queryExec = dbsetup.QueryExecutor(database=application.db)
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

queryExec.save()在查询失败时抛出异常,我想在请求处理函数内部知道它是否发生。在try和except块中嵌入queryExec.save()不起作用。显然,我可以将其他参数(引用?)传递给queryExec.save(),或者将某种状态参数添加到QueryExecutor类本身,但我想知道是否有更优雅的方法来解决这个问题?

编辑: 经过一些修改后:

class TestEx(Exception): pass

@gen.engine
def _run(self, query):
    self.db.execute(query, callback = (yield gen.Callback('q')))
    try:
        cursor = yield momoko.WaitOp('q')
    except Exception as error:
        print(str(error))
        raise TestEx("test exception")

try:
    queryExec.save("users", userdata)
except dbsetup.TestEx as ex:
    print("exception caught in caller function")
    self.redirect("templates/login.html")

我进入控制台:

/usr/bin/python3.3 /home/tybur/PycharmProjects/tornadochat/main.py
duplicate key value violates unique constraint "unique_names"
DETAIL:  Key (name)=(testuser) already exists.

ERROR:tornado.application:Exception in callback None
Traceback (most recent call last):
  File "/home/tybur/PycharmProjects/tornadochat/dbsetup.py", line 46, in _run
    cursor = yield momoko.WaitOp('q')
  File "/usr/local/lib/python3.3/dist-packages/tornado/gen.py", line 520, in run
    next = self.yield_point.get_result()
  File "/usr/local/lib/python3.3/dist-packages/momoko/utils.py", line 59, in get_result
    raise error
  File "/usr/local/lib/python3.3/dist-packages/momoko/connection.py", line 244, in io_callback
    state = self.connection.poll()
psycopg2.IntegrityError: duplicate key value violates unique constraint "unique_names"
DETAIL:  Key (name)=(testuser) already exists.


During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.3/dist-packages/tornado/ioloop.py", line 688, in start
    self._handlers[fd](fd, events)
  File "/usr/local/lib/python3.3/dist-packages/tornado/stack_context.py", line 331, in wrapped
    raise_exc_info(exc)
  File "<string>", line 3, in raise_exc_info
  File "/usr/local/lib/python3.3/dist-packages/tornado/stack_context.py", line 302, in wrapped
    ret = fn(*args, **kwargs)
  File "/usr/local/lib/python3.3/dist-packages/momoko/connection.py", line 248, in io_callback
    self.callback(error)
  File "/usr/local/lib/python3.3/dist-packages/tornado/stack_context.py", line 331, in wrapped
    raise_exc_info(exc)
  File "<string>", line 3, in raise_exc_info
  File "/usr/local/lib/python3.3/dist-packages/tornado/stack_context.py", line 302, in wrapped
    ret = fn(*args, **kwargs)
  File "/usr/local/lib/python3.3/dist-packages/tornado/gen.py", line 574, in inner
    self.set_result(key, result)
  File "/usr/local/lib/python3.3/dist-packages/tornado/gen.py", line 500, in set_result
    self.run()
  File "/usr/local/lib/python3.3/dist-packages/tornado/gen.py", line 529, in run
    yielded = self.gen.throw(*exc_info)
  File "/home/tybur/PycharmProjects/tornadochat/dbsetup.py", line 49, in _run
    raise TestEx("test exception")
dbsetup.TestEx: test exception

1 个答案:

答案 0 :(得分:1)

save()不会引发异常;它开始调用_run但不等待它,因此除了要记录之外,没有任何地方可以去除异常。要解决此问题,您应遵循以下三条规则:

  • 除非您有特定原因要使用@gen.engine,否则您应该使用@gen.coroutine代替,这会使事情更像普通函数。
  • 任何调用协程的方法也必须是协程。这条规则有例外,但它们很微妙,除非你能更好地处理异步编程,否则你应该遵循它。由于只有协程可以调用协程,因此您只能在某些位置启动链 - 通常在Tornado文档中描述为“可能返回Future”的方法(包括RequestHandler get / post / etc方法)。
  • 对协同程序的调用通常应以“yield”为前缀,以等待其结果。如果在调用协程时不使用“yield”,则应保存其返回值(Future,这是其实际结果的占位符)并稍后生成(您可能希望这样做并行启动多个协同程序并立即等待它们。)

因此,在这种情况下,请设置save()_run()post()协同程序,并在调用_run()save()时使用yield关键字。