Verwenden Sie Python Decorators, um Codeblöcke erneut zu versuchen

Olorunfemi Akinlua 21 Juni 2023
  1. Wichtigkeit von Wiederholen-Dekorateuren
  2. Verwenden Sie @retry, um Codeblöcke in Python erneut zu versuchen
  3. Verwenden Sie tenacity, um Codeblöcke in Python erneut zu versuchen
Verwenden Sie Python Decorators, um Codeblöcke erneut zu versuchen

Wir können eine Funktion oder Klasse mit einem Decorator modifizieren, um das Verhalten der Funktion zu erweitern, ohne sie dauerhaft zu ändern. In diesem Artikel wird beschrieben, wie Sie retry-Dekoratoren verwenden, um eine vorhandene Funktion zu ändern, ohne Änderungen an der besagten Funktion vorzunehmen.

In diesem Fall wiederholt die Modifikation die Funktion mehrmals in einer bestimmten Situation, in der ihr Rückgabewert von dem abweichen könnte, was wir wollen.

Wichtigkeit von Wiederholen-Dekorateuren

Wir können Decorators verwenden, um das Verhalten einer bestimmten Funktion zu erweitern, und wir können ganz einfach Decorators erstellen, um diese Funktion zu ändern, selbst wenn wir keinen Zugriff darauf haben oder sie nicht ändern möchten.

Wir brauchen diese Funktion oft auf eine ziemlich spezifische Art und Weise, und hier kommen Python-Dekoratoren ins Spiel. Erstellen wir also eine einfache Funktion, um zu zeigen, wie Dekoratoren funktionieren.

Die einfache Funktion quotient() nimmt zwei Argumente und dividiert das erste Argument durch das zweite Argument.

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


print(quotient(3, 7))

Ausgang:

0.42857142857142855

Wenn wir jedoch möchten, dass das Divisionsergebnis immer so ist, dass die größere Zahl dividiert wird (das Ergebnis ist also 2.3333333333333335), können wir entweder den Code ändern oder Dekoratoren verwenden.

Mit Dekoratoren können wir das Verhalten der Funktion erweitern, ohne ihren Codeblock zu ändern.

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

Ausgang:

2.3333333333333335

Die improv()-Funktion ist die Decorator-Funktion, die die quotient()-Funktion als Argument nimmt und eine innere Funktion enthält, die das Argument der quotient()-Funktion nimmt und die zusätzliche Funktionalität einbringt, die Sie benötigen hinzufügen.

Mit Decorators können wir jetzt einer bestimmten Funktion eine Wiederholen-Funktion hinzufügen, insbesondere bei Funktionen, auf die wir keinen Zugriff haben.

retry-Decorators sind in Szenarien hilfreich, in denen unvorhersehbare Verhaltensweisen oder Fehler auftreten können und Sie dieselbe Operation erneut versuchen möchten, wenn sie auftreten.

Ein typisches Beispiel ist die Behandlung einer fehlgeschlagenen Anfrage innerhalb einer for-Schleife. In solchen Szenarien können wir retry-Decorators verwenden, um die Wiederholung dieser bestimmten Anfrage eine bestimmte Anzahl von Malen zu verwalten.

Verwenden Sie @retry, um Codeblöcke in Python erneut zu versuchen

Für retry-Decorators gibt es verschiedene Bibliotheken, die diese Funktion bereitstellen, und eine dieser Bibliotheken ist die retrying-Bibliothek.

Damit können Sie Warten- und Stopp-Bedingungen von Ausnahmen bis zu erwarteten Rückgabeergebnissen festlegen. Um die Bibliothek retrying zu installieren, können wir den Befehl pip wie folgt verwenden:

pip install retrying

Lassen Sie uns nun eine Funktion erstellen, die zufällig Zahlen zwischen 0 und 10 erstellt, aber einen ValueError auslöst, wenn wir eine Situation haben, in der die Zahl größer als 1 ist.

import random


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


print(generateRandomly())

Die Codeausgabe sieht wie folgt aus, wenn die zu diesem Zeitpunkt generierte Zahl größer als eins ist.

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

Wir können keine Situation haben, in der ein ValueError in unseren Code geworfen wird, also können wir einen retry-Decorator einführen, um die Funktion generateRandomly() erneut zu versuchen, bis sie keinen ValueError auslöst.

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

Ausgang:

Finally Generated.

Jetzt wiederholt der retry-Decorator die random-Operation, bis es keinen ValueError mehr gibt und wir nur die Zeichenfolge Finally Generated. haben.

Wir können sehen, wie oft der Code generateRandomly() wiederholt hat, indem wir eine print()-Anweisung in den if-Block einfügen.

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

Ausgang:

1
1
1
1
1
1
1
Finally Generated.

Hier 8, aber es könnte anders sein, wenn Sie den Code ausführen. Wir können jedoch keine Situation haben, in der der Code für eine lange Zeit wiederholt versucht. Wir haben also Argumente wie stop_max_attempt_number und 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())

Ausgang:

1
1
1
Finally Generated.

Die Funktion wird nur 5 Mal wiederholt, aber entweder ist sie vor dem fünften Mal erfolgreich, gibt den Wert Finally Generated. zurück, oder sie tut es nicht und wirft den 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

Verwenden Sie tenacity, um Codeblöcke in Python erneut zu versuchen

Die retrying-Bibliothek kann etwas eigenartig sein und wird nicht mehr gepflegt, aber die tenacity-Bibliothek bietet all ihre Funktionen mit mehr verfügbaren Tools.

Um tenacity zu installieren, verwenden Sie den folgenden pip-Befehl:

pip install tenacity

Wir können den gleichen Code mit einem stop-Versuch bei 3 ausprobieren.

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

Die Ausgabe des Codes, wenn die generierte Zufallszahl innerhalb des Zeitrahmens von drei Versuchen kleiner als 1 ist.

1
Finally Generated.

Ist dies jedoch nicht der Fall, wird die folgende Ausgabe ausgegeben.

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

Verwandter Artikel - Python Decorator