Восстановление генератора с помощью декоратора
Давайте иметь класс, у которого есть функция, которая время от времени завершается ошибкой, но после некоторых действий она работает просто отлично.
Примером из реальной жизни будет Mysql Query, который поднимает_mysql_exceptions.OperationalError: (2006, 'MySQL server has gone away')
но после переподключения клиента все работает нормально.
Я пытался написать декоратор для этого:
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
Но мне любопытно, есть ли более элегантный (более питонический) способ сделать это.Есть ли способ заставить Python запускать весь код до первогоyield
а такжезатем Подождите?
Я знаю о возможности просто позвонитьreturn tuple(func(self, *args, **kwargs))
но я хочу избежать загрузки всех записей одновременно.