Generador de recuperación utilizando decorador

Tengamos una clase que tiene una función que falla de vez en cuando, pero después de algunas acciones simplemente funciona perfectamente.

El ejemplo de la vida real sería Mysql Query que plantea_mysql_exceptions.OperationalError: (2006, 'MySQL server has gone away') pero después de la reconexión del cliente funciona bien.

He intentado escribir decorador para esto:

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)

Y si el cliente pierde la conexión, se reconecta silenciosamente y todos están contentos.

Pero que pasa si quiero transformarget_data() al generador (y usaryield declaración):

    @_auto_reconnect_wrapper
    def get_data(self):
        sql = '...'
        cursor = self.connection.execute(sql)
        for row in cursor:
            yield row

        cursor.close()

Bueno, el ejemplo anterior no funcionará porque la función interna ya devolvió el generador y se interrumpirá después de llamar primeronext().

Según tengo entendido si Python veyield dentro del método solo cede el control de inmediato (sin ejecutar una sola declaración) y espera primeronext().

He logrado hacer que funcione reemplazando:

return func(self, *args, **kwargs)

Con:

for row in func(self, *args, **kwargs):
    yield row

Pero tengo curiosidad por saber si hay una forma más elegante (más pitónica) de hacer esto.¿Hay alguna manera de hacer que Python ejecute todo el código hasta primeroyield yentonces ¿Espere?

Soy consciente de la posibilidad de simplemente llamarreturn tuple(func(self, *args, **kwargs)) pero quiero evitar cargar todos los registros a la vez.

Respuestas a la pregunta(2)

Su respuesta a la pregunta