psagrera
psagrera

Reputation: 141

Using decorator inside a function

Inside a function I'm using a retry mechanism like that (always in a try/except block):

        def load(self):
            [........]
            # Retry mechanism for locking database 
            for i in range(1, max_connection_retries+1):                        
                try:
                    cu.lock()
                    break
                except LockError as l_error:
                    if i < max_connection_retries:
                        sleep(20)
                        continue
                    else:
                        raise ContinuableError (logger.console(datetime.now().time().strftime ("%b %d %H:%M:%S") + ' ERROR:Impossible to lock the database after %i retries' % max_connection_retries))
        [.......]

I'm using this mechanism several times in others part of the same function and in other functions. It would be possible to apply a decorator to only this part of the code ? something like that:

        def load(self): 
            [.......]
            @retry(max=5,message='blablabla')                       
            try:
                cu.lock()
                break
            except LockError as l_error:

            [.......]

            @retry(max=5)                       
            try:
                cu.unlock()
                break
            except LockError as l_error:

If so, could you help me showing me an example of a decorator for doing such task ?

Upvotes: 6

Views: 8703

Answers (2)

Mikhail Gerasimov
Mikhail Gerasimov

Reputation: 39536

As said decorator can be applied only to function, but can move "retry" logic to separate function and pass cu.lock/cu.unlock (and other stuff like max, messge) to that function as params:

def retry(func, tries, message):
    for i in range(1, tries+1):                        
        try:
            func()  # <- call passed function
            break
        except LockError as l_error:
            if i < tries:
                sleep(20)
                continue
            else:
                raise ContinuableError('...')

def load(self):
    retry(cu.lock, tries=5, message='blablabla')  # pass cu.lock to be called

    retry(cu.unlock, tries=5, message='blablabla')  # pass cu.unlock to be called

Upvotes: 2

chepner
chepner

Reputation: 530970

The decorator syntax is just syntactic sugar for

# f could be a class as well
def f():
    ...
f = retry(f)

It cannot be applied to arbitrary anonymous blocks of code. The main purpose of a decorator is to rebind a name, and an anonymous block, by definition, has no name.

What you would need to do is refactor the code you want to retry into a function that gets decorated. For example,

@retry(max=5, message='blablabla')
def get_lock():
    try:
        cu.lock()
    except LockError as l_error:
        # Some action dependent on the implementation of retry


def load(self):
    get_lock()

Upvotes: 5

Related Questions