So definieren Sie Ihre eigenen Ausnahmeklassen in Python

Hallo Habr!



Ihr Interesse an dem neuen Buch " Python Pro Secrets " hat uns überzeugt, dass die Geschichte der Python-Macken es verdient, fortgesetzt zu werden. Heute bieten wir an, ein kleines Tutorial zum Erstellen von benutzerdefinierten (im Text - Ihren eigenen) Ausnahmeklassen zu lesen. Der Autor fand es interessant, es ist schwierig, ihm zu widersprechen, dass der wichtigste Vorteil einer Ausnahme die Vollständigkeit und Klarheit der Fehlermeldung ist. Ein Teil des Codes aus dem Original besteht aus Bildern.



Willkommen bei Katze.



Erstellen Sie Ihre eigenen Fehlerklassen



Python bietet die Möglichkeit, eigene Ausnahmeklassen zu erstellen. Durch das Erstellen solcher Klassen können Sie das Design der Klassen in Ihrer Anwendung diversifizieren. Eine benutzerdefinierte Fehlerklasse kann Fehler protokollieren und das Objekt untersuchen. Wir definieren, was die Ausnahmeklasse tut, obwohl eine benutzerdefinierte Klasse normalerweise kaum mehr kann, als eine Nachricht anzuzeigen.



Natürlich ist der Fehlertyp selbst wichtig, und wir erstellen häufig eigene Fehlertypen, um auf eine bestimmte Situation hinzuweisen, die auf Python-Sprachebene normalerweise nicht behandelt wird. Auf diese Weise wissen Benutzer der Klasse genau, was passiert, wenn sie auf diesen Fehler stoßen.



Dieser Artikel ist in zwei Teile gegliedert. Zunächst definieren wir eine Ausnahmeklasse für sich. Anschließend zeigen wir, wie wir unsere eigenen Ausnahmeklassen in unsere Python-Programme integrieren können und wie wir so die Benutzerfreundlichkeit der von uns entworfenen Klassen verbessern können.



Benutzerdefinierte Ausnahmeklasse MyCustomError



Das Auslösen einer Ausnahme erfordert die Methoden __init__()



und __str__()



.




Beim Auslösen einer Ausnahme erstellen wir bereits eine Instanz der Ausnahme und zeigen sie gleichzeitig auf dem Bildschirm an. Schauen wir uns unsere unten gezeigte benutzerdefinierte Ausnahmeklasse genauer an.







Die obige MyCustomError Klasse hat zwei magische Methoden, __init__



und __str__



, die automatisch bei der Ausnahmebehandlung aufgerufen werden. Die Methode Init



wird aufgerufen, wenn die Instanz erstellt wird, und die Methode str



wird aufgerufen, wenn die Instanz angezeigt wird. Wenn eine Ausnahme ausgelöst wird, werden diese beiden Methoden daher normalerweise unmittelbar nacheinander aufgerufen. Die Python-Ausnahme-Throw-Anweisung versetzt ein Programm in einen Fehlerzustand.



In der Argumentliste der Methode __init__



ist *args



. Eine Komponente *args



ist ein spezieller Mustervergleichsmodus, der in Funktionen und Methoden verwendet wird. Sie können mehrere Argumente übergeben und die übergebenen Argumente als Tupel speichern. Gleichzeitig können Sie jedoch überhaupt keine Argumente übergeben.



In unserem Fall können wir sagen, dass wenn MyCustomError



Argumente an den Konstruktor übergeben wurden , wir das erste übergebene Argument nehmen und es einem Attribut message



im Objekt zuweisen . Wenn keine Argumente übergeben wurden, wird dem Attribut message



ein Wert zugewiesen None



.



Im ersten Beispiel wird die Ausnahme MyCustomError



ohne Argumente ausgelöst , also das Attribut message



Diesem Objekt wird ein Wert zugewiesen None



. Eine Methode wird aufgerufen str



und zeigt die Meldung "MyCustomError-Meldung wurde ausgelöst" an.







Die Ausnahme MyCustomError



wird ohne Argumente ausgelöst (Klammern sind leer). Mit anderen Worten, ein solches Objektdesign sieht nicht standardisiert aus. Dies ist jedoch nur syntaktische Unterstützung, die in Python beim Auslösen einer Ausnahme bereitgestellt wird.



Im zweiten Beispiel wird es MyCustomError



mit einem String-Argument 'Wir haben ein Problem' übergeben. Es wird als Attribut des message



Objekts festgelegt und als Fehlermeldung angezeigt, wenn eine Ausnahme ausgelöst wird.







Der Code für die MyCustomError-Ausnahmeklasse ist hier...



class MyCustomError(Exception):
    def __init__(self, *args):
        if args:
            self.message = args[0]
        else:
            self.message = None

    def __str__(self):
        print('calling str')
        if self.message:
            return 'MyCustomError, {0} '.format(self.message)
        else:
            return 'MyCustomError has been raised'


#  MyCustomError

raise MyCustomError('We have a problem')
      
      





CustomIntFloatDic-Klasse



Wir erstellen unser eigenes Wörterbuch, dessen Werte nur Ganzzahlen und Gleitkommazahlen sein können.



Lassen Sie uns zeigen, wie Sie Fehlerklassen einfach und sinnvoll in unsere eigenen Programme einfügen können. Zunächst werde ich ein leicht erfundenes Beispiel anbieten. In diesem fiktiven Beispiel werde ich mein eigenes Wörterbuch erstellen, das nur Ganzzahlen oder Gleitkommazahlen akzeptieren kann.



Wenn der Benutzer versucht, einen anderen Datentyp als Wert in diesem Wörterbuch anzugeben, wird eine Ausnahme ausgelöst. Diese Ausnahme bietet dem Benutzer nützliche Informationen zur Verwendung dieses Wörterbuchs. In unserem Fall informiert diese Nachricht den Benutzer direkt darüber, dass in diesem Wörterbuch nur Ganzzahlen oder Gleitkommazahlen als Werte angegeben werden können.



Beachten Sie beim Erstellen Ihres eigenen Wörterbuchs, dass es zwei Stellen gibt, an denen dem Wörterbuch Werte hinzugefügt werden können. Dies kann zum einen in der init-Methode beim Erstellen eines Objekts geschehen (zu diesem Zeitpunkt können dem Objekt bereits Schlüssel und Werte zugewiesen werden) und zum anderen beim Festlegen von Schlüsseln und Werten direkt im Wörterbuch. An beiden Stellen müssen Sie Code schreiben, um sicherzustellen, dass der Wert nur vom Typ int



oder sein kann float



.



Zuerst definiere ich die CustomIntFloatDict-Klasse, die von der integrierten Klasse erbt dict



. dict



in einer Liste von Argumenten übergeben, die in Klammern stehen und dem Klassennamen folgen CustomIntFloatDict



.



Wenn eine Klasse instanziiert wird CustomIntFloatDict



Darüber hinaus werden keine Argumente an die Schlüssel- und Wertparameter übergeben, sondern auf gesetzt None



. Der Ausdruck wird if



wie folgt interpretiert: Wenn entweder der Schlüssel gleich None



oder der Wert gleich ist None



, wird mit dem Objekt eine Methode aufgerufen get_dict()



, die das Attribut empty_dict



zurückgibt. Ein solches Attribut für ein Objekt zeigt auf eine leere Liste. Denken Sie daran, dass Klassenattribute für alle Instanzen der Klasse verfügbar sind.







Der Zweck dieser Klasse besteht darin, dem Benutzer das Übergeben einer Liste oder eines Tupels mit den darin enthaltenen Schlüsseln und Werten zu ermöglichen. Wenn der Benutzer eine Liste oder ein Tupel eingibt, das nach Schlüsseln und Werten sucht, werden diese beiden Aufzählungssätze mithilfe der Funktion verkettet zip



die Python-Sprache. Eine verknüpfte Variable, die auf ein Objekt zeigt, zip



ist iterierbar und Tupel können nicht entpackt werden. Durch Durchlaufen der Tupel überprüfe ich, ob val eine Instanz der Klasse int



oder ist float



. Wenn es val



zu keiner dieser Klassen gehört, löse ich IntFloatValueError



meine eigene Ausnahme und übergebe val als Argument.



IntFloatValueError-Ausnahmeklasse



Wenn eine Ausnahme ausgelöst wird, IntFloatValueError



erstellen wir eine Instanz der Klasse IntFloatValueError



und zeigen sie gleichzeitig auf dem Bildschirm an. Dies bedeutet, dass die magischen Methoden init



und aufgerufen werden str



.



Der Wert, der die ausgelöste Ausnahme verursacht hat, wird als Attribut für value



die Klasse festgelegt IntFloatValueError



. Beim Aufrufen der magic str-Methode erhält der Benutzer eine Fehlermeldung, dass der Wert init



in CustomIntFloatDict



ungültig ist. Der Benutzer weiß, was zu tun ist, um diesen Fehler zu beheben.







Ausnahmeklassen IntFloatValueError



und KeyValueConstructError











Wenn keine Ausnahme ausgelöst wird, also alle val



vom verketteten Objekt sind vom Typ int



oder float



, dann werden sie mit gesetzt __setitem__()



, und die Methode aus der übergeordneten Klasse erledigt alles für uns dict



, wie unten gezeigt.







KeyValueConstructError-Klasse



Was passiert, wenn der Benutzer einen Typ eingibt, der keine Liste oder ein Tupel von Schlüsseln und Werten ist?



Auch dieses Beispiel ist etwas künstlich, aber es ist praktisch, Ihnen zu zeigen, wie Sie Ihre eigenen Ausnahmeklassen verwenden können.



Wenn der Benutzer die Schlüssel und Werte nicht als Liste oder Tupel angibt, wird eine Ausnahme ausgelöst KeyValueConstructError



. Mit dieser Ausnahme soll der Benutzer darüber informiert werden, dass zum Schreiben von Schlüsseln und Werten in ein Objekt CustomIntFloatDict



im init



Klassenkonstruktor eine Liste oder ein Tupel angegeben werden muss CustomIntFloatDict



.



Im obigen Beispiel als zweites Argument an den Konstruktor init



viel wurde bestanden und eine Ausnahme wurde aus diesem Grund geworfen KeyValueConstructError



. Der Vorteil der angezeigten Fehlermeldung besteht darin, dass die angezeigte Fehlermeldung den Benutzer darüber informiert, dass die einzufügenden Schlüssel und Werte entweder als Liste oder als Tupel gemeldet werden müssen.



Wenn eine Ausnahme ausgelöst wird, wird erneut eine KeyValueConstructError-Instanz erstellt und der Schlüssel und die Werte werden als Argumente an den KeyValueConstructError-Konstruktor übergeben. Sie werden als Werte der Schlüssel- und Wertattribute von KeyValueConstructError festgelegt und in der Methode __str__ verwendet, um eine aussagekräftige Fehlermeldung zu generieren, wenn die Nachricht auf dem Bildschirm angezeigt wird.



Außerdem füge ich sogar die Datentypen hinzu, die den dem Konstruktor hinzugefügten Objekten inhärent sind init



- Ich mache das aus Gründen der Klarheit.







Festlegen von Schlüssel und Wert in CustomIntFloatDict



CustomIntFloatDict



erbt von dict



. Dies bedeutet, dass es genau wie ein Wörterbuch funktioniert, außer an den Stellen, an denen wir sein Verhalten selektiv ändern möchten.



__setitem__



Ist eine magische Methode, die beim Festlegen eines Schlüssels und eines Werts in einem Wörterbuch aufgerufen wird. In unserer Implementierung setitem



prüfen wir, ob der Wert vom Typ int



oder ist float



, und erst nach einer erfolgreichen Prüfung kann er im Wörterbuch festgelegt werden. Wenn die Prüfung fehlschlägt, können Sie die Ausnahmeklasse erneut verwenden IntFloatValueError



. Hier können Sie sicherstellen, dass beim Versuch, eine Zeichenfolge ‘bad_value’



als Wert im Wörterbuch test_4



festzulegen, eine Ausnahme angezeigt wird.







Der gesamte Code für dieses Tutorial wird unten angezeigt und auf Github veröffentlicht .



#  ,        int  float  

class IntFloatValueError(Exception):
    def __init__(self, value):
        self.value = value

    def __str__(self):
        return '{} is invalid input, CustomIntFloatDict can only accept ' \
               'integers and floats as its values'.format(self.value)


class KeyValueContructError(Exception):
    def __init__(self, key, value):
        self.key = key
        self.value = value

    def __str__(self):
        return 'keys and values need to be passed as either list or tuple' + '\n' + \
                ' {} is of type: '.format(self.key) + str(type(self.key)) + '\n' + \
                ' {} is of type: '.format(self.value) + str(type(self.value))


class CustomIntFloatDict(dict):

    empty_dict = {}

    def __init__(self, key=None, value=None):

        if key is None or value is None:
            self.get_dict()

        elif not isinstance(key, (tuple, list,)) or not isinstance(value, (tuple, list)):
            raise KeyValueContructError(key, value)
        else:
            zipped = zip(key, value)
            for k, val in zipped:
                if not isinstance(val, (int, float)):
                    raise IntFloatValueError(val)
                dict.__setitem__(self, k, val)

    def get_dict(self):
        return self.empty_dict

    def __setitem__(self, key, value):
        if not isinstance(value, (int, float)):
            raise IntFloatValueError(value)
        return dict.__setitem__(self, key, value)


#  

# test_1 = CustomIntFloatDict()
# print(test_1)
# test_2 = CustomIntFloatDict({'a', 'b'}, [1, 2])
# print(test_2)
# test_3 = CustomIntFloatDict(('x', 'y', 'z'), (10, 'twenty', 30))
# print(test_3)
# test_4 = CustomIntFloatDict(('x', 'y', 'z'), (10, 20, 30))
# print(test_4)
# test_4['r'] = 1.3
# print(test_4)
# test_4['key'] = 'bad_value'
      
      





Fazit



Wenn Sie Ihre eigenen Ausnahmen erstellen, wird die Arbeit mit der Klasse viel bequemer. Die Ausnahmeklasse sollte magische Methoden haben init



und str



dass werden automatisch während der Ausnahmebehandlung genannt. Es liegt ganz bei Ihnen, was Ihre eigene Ausnahmeklasse tun wird. Unter den gezeigten Methoden befinden sich diejenigen, die für die Inspektion eines Objekts und die Anzeige einer informativen Fehlermeldung auf dem Bildschirm verantwortlich sind.



Wie auch immer, Ausnahmeklassen erleichtern die Behandlung auftretender Fehler erheblich!



All Articles