Восстановление генератора с помощью декоратора

Давайте иметь класс, у которого есть функция, которая время от времени завершается ошибкой, но после некоторых действий она работает просто отлично.

Примером из реальной жизни будет 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)) но я хочу избежать загрузки всех записей одновременно.

Ответы на вопрос(2)

Ваш ответ на вопрос