【发布时间】:2014-12-26 15:42:45
【问题描述】:
让我们有一个类,它的功能有时会失败,但经过一些操作后它就可以正常工作。
现实生活中的例子是引发_mysql_exceptions.OperationalError: (2006, 'MySQL server has gone away')但在客户端重新连接后它工作正常的Mysql Query。
我已经尝试为此编写装饰器:
def _auto_reconnect_wrapper(func):
''' Tries to reconnects dead connection
'''
def inner(self, *args, _retry=True, **kwargs):
try:
return func(self, *args, **kwargs)
except Mysql.My.OperationalError as e:
# No retry? Rethrow
if not _retry:
raise
# Handle server connection errors only
# http://dev.mysql.com/doc/refman/5.0/en/error-messages-client.html
if (e.code < 2000) or (e.code > 2055):
raise
# Reconnect
self.connection.reconnect()
# Retry
return inner(self, *args, _retry=False, **kwargs)
return inner
class A(object):
...
@_auto_reconnect_wrapper
def get_data(self):
sql = '...'
return self.connection.fetch_rows(sql)
如果客户端失去连接,它只是默默地重新连接,每个人都很高兴。
但是如果我想将get_data() 转换为生成器(并使用yield 语句)怎么办:
@_auto_reconnect_wrapper
def get_data(self):
sql = '...'
cursor = self.connection.execute(sql)
for row in cursor:
yield row
cursor.close()
好吧,前面的例子不起作用,因为内部函数已经返回了生成器,它会在第一次调用 next() 后中断。
据我了解,如果 python 在方法中看到 yield,它只会立即产生控制权(不执行单个语句)并等待第一个 next()。
我已经设法通过替换:
return func(self, *args, **kwargs)
与:
for row in func(self, *args, **kwargs):
yield row
但我很好奇是否有更优雅(更pythonic)的方式来做到这一点。 有没有办法让 python 运行所有代码到第一个 yield 然后然后等待?
我知道只调用return tuple(func(self, *args, **kwargs)) 的可能性,但我想避免一次加载所有记录。
【问题讨论】:
标签: python python-3.x decorator yield