Mam dwie różne funkcje, które wychwytują te same wyjątki, na przykład:

def func1():
    try:
        # ...do something
    except FileNotFoundError as e:
        print(e)
    except NotADirectoryError as e:
        print(e)

def func2():
    try:
        # ...do something else
    except FileNotFoundError as e:
        print(e)
    except NotADirectoryError as e:
        print(e)

Jak mogę uniknąć pisania tych identycznych wyjątków dla każdej funkcji?

Mój idealny scenariusz byłby taki:

def func1():
    # ... do something while catching those exceptions without explicitly stating them here.

def func2():
    # ... do something while catching those exceptions without explicitly stating them here.
1
tera_789 5 marzec 2020, 10:55

2 odpowiedzi

Najlepsza odpowiedź

Możesz to zrobić za pomocą dekoratorów, ale ogólnie rzecz biorąc, obsługa wyjątków wewnątrz metod funkcji lub klas jest złą praktyką. Wyjątki powinny być zgłaszane w funkcji / metodach i powinny być obsługiwane w zakresie zewnętrznym.

Niemniej jednak kod wygląda następująco:

# create decorator function it can be used in any class, with any function or method:
def my_decorator(f):
    def decorated_func(*args, **kwargs):
        try:
            f(*args, **kwargs)
        except ValueError as e:
            print(e)
        except TypeError as e:
            print(e)
    return decorated_func


# some class with some static methods:
class MyClass:
    @my_decorator
    def __init__(self, x, y):
        if x == 5:
            raise TypeError("C")
        self.x = x
        self.y = y
        print(self.x/self.y)

    @staticmethod
    @my_decorator
    def test(a, b, c):
        if a == 1:
            raise ValueError("A")
        print(a + b + c)

    @staticmethod
    @my_decorator
    def test_two(a, b):
        if b == 1:
            raise TypeError("B")
        print(a * b)


if __name__ == '__main__':
    MyClass.test(a=2, b=2, c=3)
    MyClass.test(a=1, b=2, c=3)
    MyClass.test_two(a=1, b=1)
    MyClass.test_two(a=2, b=2)

    z = MyClass(1, 1)
    z2 = MyClass(5, 5)

Właściwie prawidłowy sposób obsługi błędów powinien wyglądać następująco, wszystkie wyjątki są obsługiwane w kodzie „klienta”, a nie w zakresie metod i funkcji. Jest to najlepszy sposób obsługi wyjątków, jeśli zamierzasz używać swojej biblioteki w innych aplikacjach:

def some_f(x, y):
    if x == 1:
        raise Exception("x = 1 it is bad")
    print(x + y)


class SomeClass:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def sum_them(self):
        if self.x == 1:
            raise Exception("Incorrect x")
        print(self.x + self.y)


if __name__ == '__main__':
    # so called "client" code
    try:
        some_f(1, 3)
    except Exception as ex:
        print(ex)

    try:
        z = SomeClass(1, 2)
        z.sum_them()
    except Exception as ex:
        print(ex)

1
Artiom Kozyrev 5 marzec 2020, 08:32

Mógłbyś napisać dekoratora.

from functools import wraps


def just_report_file_errors(fn):
    @wraps(fn)
    def decorator(*args, **kwargs):
        try:
            return fn(*args, **kwargs)
        except FileNotFoundError as e:
            print(e)
        except NotADirectoryError as e:
            print(e)

    return decorator


@just_report_file_errors
def func1():
    pass  # do thing...


@just_report_file_errors
def func2():
    pass  # do thing...
2
AKX 5 marzec 2020, 08:02