迹忆客 专注技术分享

当前位置:主页 > 学无止境 > 编程语言 > Python >

使用 Python 装饰器重试代码块

作者:迹忆客 最近更新:2023/06/17 浏览次数:

我们可以用装饰器修改一个函数或类来扩展函数的行为,而不用永久地改变它。 本文讨论如何使用重试装饰器修改现有函数而不更改所述函数。

在这种情况下,修改会在给定情况下多次重试函数,其返回值可能与我们想要的不同。


@retry 装饰器的重要性

我们可以使用装饰器来扩展特定函数的行为,我们可以轻松地创建装饰器来修改该函数,即使我们无法访问它或不想更改它。

我们可能经常需要该函数的特定方式,这就是 Python 装饰器的用武之地。所以让我们创建一个简单的函数来展示装饰器的工作原理。

简单的函数 quotient() 接受两个参数并将第一个参数除以第二个参数。

def quotient(a, b):
    return a / b

print(quotient(3, 7))

输出:

0.42857142857142855

但是,如果我们希望除法结果始终是较大的数被除(因此结果将是 2.3333333333333335),我们可以更改代码或使用装饰器。

使用装饰器,我们可以在不更改其代码块的情况下扩展函数的行为。

def improv(func):
    def inner(a, b):
        if a < b:
            a, b = b, a
        return func(a, b)

    return inner

@improv
def quotient(a, b):
    return a / b

print(quotient(3, 7))

输出:

2.3333333333333335

improv() 函数是一个装饰函数,它将 quotient() 函数作为其参数,并包含一个内部函数,该函数采用 quotient() 函数的参数并引入您需要添加的附加功能。

现在,使用装饰器,我们可以在特定函数上添加重试功能,尤其是对于我们无权访问的函数。

重试装饰器在可能存在不可预测的行为或错误的情况下很有用,并且您希望在它们发生时再次重试相同的操作。

一个典型的例子是在 for 循环中处理失败的请求。 在这种情况下,我们可以使用 @retry 装饰器来管理重试该特定请求指定次数。


在 Python 中使用 @retry 重试代码块

对于重试装饰器,有不同的库提供此功能,其中一个库是 retrying 库。

使用它,您可以指定从 Exceptions 到预期返回结果的等待和停止条件。 要安装 retrying 库,我们可以使用 pip 命令,如下所示:

$ pip install retrying

现在,让我们创建一个函数,它随机创建 0 到 10 之间的数字,但当我们遇到数字大于 1 的情况时会引发 ValueError。

import random

def generateRandomly():
    if random.randint(0, 10) > 1:
        raise ValueError("Number generated is greater than one")
    else:
        return "Finally Generated."

print(generateRandomly())

如果此时生成的数字大于 1,代码输出将如下所示。

Traceback (most recent call last):
  File "c:\Users\jiyik\Documents\Python\SFTP\test.py", line 11, in <module>
    print(generateRandomly())
  File "c:\Users\jiyik\Documents\Python\SFTP\test.py", line 6, in generateRandomly
    raise ValueError("Number generated is greater than one")
ValueError: Number generated is greater than one

我们不能在代码中抛出 ValueError 的情况,因此我们可以引入重试装饰器来重试 generateRandomly() 函数,直到它不引发 ValueError。

import random
from retrying import retry

@retry
def generateRandomly():
    if random.randint(0, 10) > 1:
        raise ValueError("Number generated is greater than one")
    else:
        return "Finally Generated."

print(generateRandomly())

输出:

Finally Generated.

现在,重试装饰器重试随机操作,直到它没有 ValueError,我们只有字符串 Finally Generated..

通过在 if 块中引入 print() 语句,我们可以看到代码重试 generateRandomly() 的次数。

import random
from retrying import retry

@retry
def generateRandomly():
    if random.randint(0, 10) > 1:
        print("1")
        raise ValueError("Number generated is greater than one")
    else:
        return "Finally Generated."

print(generateRandomly())

输出:

1
1
1
1
1
1
1
Finally Generated.

此处为 8,但运行代码时可能会有所不同。 但是,我们不能出现代码一直重试很长时间的情况。 所以,我们有像 stop_max_attempt_number 和 stop_max_delay 这样的参数。

import random
from retrying import retry

@retry(stop_max_attempt_number=5)
def generateRandomly():
    if random.randint(0, 10) > 1:
        print("1")
        raise ValueError("Number generated is greater than one")
    else:
        return "Finally Generated."

print(generateRandomly())

输出:

1
1
1
Finally Generated.

该函数只重试了 5 次,但要么在第 5 次之前成功,返回值 Finally Generated.,要么不成功并抛出 ValueError。

1
1
1
1
1
File "C:\Python310\lib\site-packages\retrying.py", line 247, in get
    six.reraise(self.value[0], self.value[1], self.value[2])
  File "C:\Python310\lib\site-packages\six.py", line 719, in reraise
    raise value
  File "C:\Python310\lib\site-packages\retrying.py", line 200, in call
    attempt = Attempt(fn(*args, **kwargs), attempt_number, False)
  File "c:\Users\jiyik\Documents\Python\SFTP\test.py", line 9, in generateRandomly
    raise ValueError("Number generated is greater than one")
ValueError: Number generated is greater than one

使用 tenacity 重试 Python 中的代码块

重试库可能有点古怪,不再维护,但坚韧库提供了所有功能,并提供了更多工具。

要安装 tenacity,请使用以下 pip 命令:

pip install tenacity

我们可以在 3 停止尝试来尝试相同的代码。

import random
from tenacity import retry, stop_after_attempt

@retry(stop=stop_after_attempt(3))
def generateRandomly():
    if random.randint(0, 10) > 1:
        print("1")
        raise ValueError("Number generated is greater than one")
    else:
        return "Finally Generated."

print(generateRandomly())

如果在三次尝试时间范围内生成的随机数小于 1,则代码的输出。

1
Finally Generated.
The above exception was the direct cause of the following exception:
1
1
1
Traceback (most recent call last):
  File "C:\Python310\lib\site-packages\tenacity\__init__.py", line 407, in __call__
    result = fn(*args, **kwargs)
  File "c:\Users\jiyik\Documents\Python\SFTP\test.py", line 9, in generateRandomly
    raise ValueError("Number generated is greater than one")
ValueError: Number generated is greater than one

上述异常是以下异常的直接原因:

Traceback (most recent call last):
  File "c:\Users\akinl\Documents\Python\SFTP\test.py", line 14, in <module>
    print(generateRandomly())
  File "C:\Python310\lib\site-packages\tenacity\__init__.py", line 324, in wrapped_f
    return self(f, *args, **kw)
  File "C:\Python310\lib\site-packages\tenacity\__init__.py", line 404, in __call__
    do = self.iter(retry_state=retry_state)
  File "C:\Python310\lib\site-packages\tenacity\__init__.py", line 361, in iter
    raise retry_exc from fut.exception()
tenacity.RetryError: RetryError[<Future at 0x29a75442c20 state=finished raised ValueError>]

转载请发邮件至 1244347461@qq.com 进行申请,经作者同意之后,转载请以链接形式注明出处

本文地址:

相关文章

Pandas read_csv()函数

发布时间:2024/04/24 浏览次数:254 分类:Python

Pandas read_csv()函数将指定的逗号分隔值(csv)文件读取到 DataFrame 中。

Pandas 追加数据到 CSV 中

发布时间:2024/04/24 浏览次数:352 分类:Python

本教程演示了如何在追加模式下使用 to_csv()向现有的 CSV 文件添加数据。

Pandas 多列合并

发布时间:2024/04/24 浏览次数:628 分类:Python

本教程介绍了如何在 Pandas 中使用 DataFrame.merge()方法合并两个 DataFrames。

Pandas loc vs iloc

发布时间:2024/04/24 浏览次数:837 分类:Python

本教程介绍了如何使用 Python 中的 loc 和 iloc 从 Pandas DataFrame 中过滤数据。

扫一扫阅读全部技术教程

社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

最新推荐

教程更新

热门标签

扫码一下
查看教程更方便