【问题标题】:Using decorator inside a function在函数中使用装饰器
【发布时间】:2016-07-09 09:10:48
【问题描述】:

在函数内部,我正在使用类似的重试机制(总是在 try/except 块中):

        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))
        [.......]

我在同一功能的其他部分和其他功能中多次使用此机制。是否可以仅对这部分代码应用装饰器?类似的东西:

        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:

如果是这样,您能帮我展示一个执行此类任务的装饰器示例吗?

【问题讨论】:

  • 装饰器只对函数起作用。另外,您为什么不在这里使用一个方法并将重试参数作为参数传递呢?看起来您每次都尝试运行相同的代码。
  • @KurtStutsman - 我不确定 OP 的具体用例,但我知道我见过旧代码,其中 retry 部分在许多函数上完成,然后重试与底层功能无关(lockunlockupdatedelete 等 - 数据库命令或其他东西)。这似乎是使用decorator 功能而不是使用maxRetries 使10 个方法混乱的完美用例。也就是说,您的第一句话是正确的,并且 OP 需要继续前进。

标签: python python-decorators


【解决方案1】:

装饰器语法只是语法糖

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

它不能应用于任意匿名代码块。装饰器的主要目的是重新绑定名称,而匿名块根据定义是没有名称的。

您需要做的是将要重试的代码重构为一个经过修饰的函数。例如,

@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()

【讨论】:

  • 感谢您的回答,我会尝试这种方法
【解决方案2】:

如上所述,装饰器只能应用于函数,但可以将“重试”逻辑移动到单独的函数并将cu.lock/cu.unlock(以及其他类似maxmessge)作为参数传递给该函数:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-04
    相关资源
    最近更新 更多