我是 Python 新手,偶然发现了异常处理的问题。我正在编写一个简单的 Tornado + momoko 应用程序。 总之,我有一个在主函数中创建的全局(?)对象,该对象属于 QueryExecutor 类。这是一个使用 momoko 处理 SQL 查询执行的简单类。
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 block 中嵌入 queryExec.save() 不起作用。显然我可以将附加参数(引用?)传递给 queryExec.save(),或者向 QueryExecutor 类本身添加某种状态参数,但我想知道是否有更优雅的方法来解决这个问题? p>
编辑: 经过一些修改:
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
最佳答案
save()
不会引发异常;它启动对 _run
的调用,但不会等待它,因此除了记录之外,异常无处可去。要解决此问题,您应该遵循三个规则:
- 除非您有特定原因使用
@gen.engine
,否则应该使用@gen.coroutine
,这会让事情的工作方式更像普通函数。 - 任何调用协程的方法也必须是协程。该规则也有异常(exception),但它们很微妙,在您更好地处理异步编程之前,您应该遵循它。由于只有协程可以调用协程,因此您只能在某些位置启动链 - 通常是 Tornado 文档中描述为“可能返回 Future”的方法(包括 RequestHandler get/post/etc 方法)<
- 对协程的调用通常应加上“yield”前缀以等待其结果。如果您在调用协程时不使用“yield”,则应该保存其返回值(一个
Future
,它是其实际结果的占位符)并稍后生成它(您可能想要这样做可以并行启动多个协程并同时等待它们)。
所以在这种情况下,制作save()
、_run()
和post()
协程,并在调用时使用yield关键字_run()
和 save()
。
关于python - Python 中响应全局对象的异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21556658/