Python 데코레이터를 사용하여 코드 블록 재시도

Olorunfemi Akinlua 2023년6월21일
  1. 재시도 데코레이터의 중요성
  2. @retry를 사용하여 Python에서 코드 블록 재시도
  3. 끈기를 사용하여 Python에서 코드 블록 재시도
Python 데코레이터를 사용하여 코드 블록 재시도

데코레이터를 사용하여 함수나 클래스를 수정하여 영구적으로 변경하지 않고 함수의 동작을 확장할 수 있습니다. 이 기사에서는 재시도 데코레이터를 사용하여 해당 기능을 변경하지 않고 기존 기능을 수정하는 방법에 대해 설명합니다.

이 경우 수정은 반환 값이 우리가 원하는 것과 다를 수 있는 주어진 상황에서 함수를 여러 번 재시도합니다.

재시도 데코레이터의 중요성

데코레이터를 사용하여 특정 기능의 동작을 확장할 수 있으며 데코레이터를 쉽게 만들어 해당 기능에 액세스할 수 없거나 변경하고 싶지 않은 경우에도 해당 기능을 수정할 수 있습니다.

우리는 종종 그 함수가 다소 특정한 방식으로 필요할 수 있으며, 여기에서 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() 함수의 인수를 취하는 내부 함수를 보유하고 필요한 추가 기능을 제공하는 데코레이터 함수입니다. 추가하다.

이제 데코레이터를 사용하여 특정 함수, 특히 액세스 권한이 없는 함수에 재시도 기능을 추가할 수 있습니다.

‘retry’ 데코레이터는 예측할 수 없는 동작이나 오류가 있을 수 있고 이러한 작업이 발생할 때 동일한 작업을 다시 시도하려는 시나리오에서 유용합니다.

일반적인 예는 for 루프 내에서 실패한 요청을 처리하는 것입니다. 이러한 시나리오에서는 재시도 데코레이터를 사용하여 특정 요청을 지정된 횟수만큼 재시도하도록 관리할 수 있습니다.

@retry를 사용하여 Python에서 코드 블록 재시도

retry 데코레이터의 경우 이 기능을 제공하는 다양한 라이브러리가 있으며 이러한 라이브러리 중 하나가 retrying 라이브러리입니다.

이를 통해 예외에서 예상 반환 결과까지 대기중지 조건을 지정할 수 있습니다. 재시도 라이브러리를 설치하려면 다음과 같이 pip 명령을 사용할 수 있습니다.

pip install retrying

이제 010 사이의 숫자를 임의로 생성하지만 숫자가 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\akinl\Documents\Python\SFTP\test.py", line 11, in <module>
    print(generateRandomly())
  File "c:\Users\akinl\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가 발생하는 상황이 있을 수 없으므로 retry 데코레이터를 도입하여 ValueError가 발생하지 않을 때까지 generateRandomly() 함수를 재시도할 수 있습니다.

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.

이제 retry 데코레이터는 ValueError가 없을 때까지 random 작업을 재시도하고 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_numberstop_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 번만 재시도되지만 다섯 번째 시도 전에 성공하거나 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\akinl\Documents\Python\SFTP\test.py", line 9, in generateRandomly
    raise ValueError("Number generated is greater than one")
ValueError: Number generated is greater than one

끈기를 사용하여 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.

그러나 그렇지 않은 경우 아래 출력이 발생합니다.

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\akinl\Documents\Python\SFTP\test.py", line 9, in generateRandomly
    raise ValueError("Number generated is greater than one")
ValueError: Number generated is greater than one

The above exception was a direct cause of the following exception:

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>]
Olorunfemi Akinlua avatar Olorunfemi Akinlua avatar

Olorunfemi is a lover of technology and computers. In addition, I write technology and coding content for developers and hobbyists. When not working, I learn to design, among other things.

LinkedIn

관련 문장 - Python Decorator