616 Stimmen

Best practice für die Verwendung von assert?

  1. Gibt es ein Leistungs- oder Code-Wartungsproblem beim Verwenden von assert als Teil des Standardcodes, anstatt es nur für Debugging-Zwecke zu verwenden?

    Ist

    assert x >= 0, 'x ist kleiner als null'

    besser oder schlechter als

    if x < 0:
        raise Exception('x ist kleiner als null')
  2. Gibt es auch eine Möglichkeit, eine Geschäftsregel festzulegen wie if x < 0 raise error, die immer überprüft wird, ohne das try/except/finally, so dass, wenn zu irgendeinem Zeitpunkt im Code x kleiner als 0 ist, ein Fehler ausgelöst wird, wie wenn Sie am Anfang einer Funktion assert x < 0 festlegen, überall innerhalb der Funktion, wo x kleiner als 0 wird, wird eine Ausnahme ausgelöst?

66 Stimmen

-O und -OO Python-Parameter werden Ihre Behauptungen beseitigen. Das sollte Ihr Denken darüber anregen, wofür es gut ist.

6 Stimmen

Der Link von Thomasz Zielinski ist defekt, er lautet nun: mail.python.org/pipermail/python-list/2013-November/660568.h‌​tml . Ich bin mir ziemlich sicher, dass pipermail eine instabile ID-Funktion hat. Ich habe andere Links innerhalb desselben pipermail gefunden, die auf dieselbe URL mit derselben Absicht verweisen.

9 Stimmen

Im Falle, dass mail.python.org/pipermail/python-list/2013-November/660568.h‌​tml erneut verschoben wird, ist es archiviert unter archive.is/5GfiG. Der Titel des Beitrags lautet "When to use assert" und ist ein ausgezeichneter Beitrag (eigentlich ein Artikel) zu den bewährten Methoden für Python assert.

882voto

Deestan Punkte 15779

Asserts sollten verwendet werden, um Bedingungen zu testen, die niemals passieren sollten. Der Zweck ist es, frühzeitig abzustürzen, falls sich das Programm in einem fehlerhaften Zustand befindet.

Ausnahmen sollten für Fehler verwendet werden, die theoretisch auftreten können, und Sie sollten fast immer Ihre eigenen Ausnahmeklassen erstellen.


Zum Beispiel, wenn Sie eine Funktion schreiben, um aus einer Konfigurationsdatei in ein dict zu lesen, sollte falsche Formatierung in der Datei einen ConfigurationSyntaxError auslösen, während Sie assert verwenden können, um sicherzustellen, dass Sie nicht None zurückgeben.


In Ihrem Beispiel, wenn x ein Wert ist, der über eine Benutzeroberfläche oder aus einer externen Quelle festgelegt wird, ist eine Ausnahme am besten.

Wenn x nur von Ihrem eigenen Code im selben Programm festgelegt wird, verwenden Sie eine Assertion.

60 Stimmen

+1 für den letzten Absatz - obwohl du ausdrücklich erwähnen solltest, dass `assert` implizit `if __debug__` enthält und möglicherweise optimiert werden kann - wie John Mee's Antwort besagt.

0 Stimmen

Wann ist eine bestimmte Bedingung unwahrscheinlich genug, um einen assert zu verwenden? Diese Regel kann nicht streng angewendet werden. Du müsstest alle Bedingungen definieren, die als unwahrscheinlich genug angesehen werden, damit diese Regel verwendbar ist.

3 Stimmen

Beim erneuten Lesen deiner Antwort denke ich, dass du wahrscheinlich nicht gemeint hast, dass Bedingungen, die niemals auftreten sollten als Regel verstanden werden sollen, sondern eher, dass der Zweck darin besteht, frühzeitig abzustürzen, wenn sich ein fehlerhafter Programmzustand ergibt, der normalerweise mit einer Bedingung zusammenfällt, die du sowieso nicht erwartest..

471voto

John Mee Punkte 46854

"assert" Anweisungen werden entfernt, wenn die Kompilierung optimiert wird. Also ja, es gibt sowohl Leistungs- als auch funktionale Unterschiede.

Der aktuelle Code-Generator erzeugt keinen Code für eine "assert" Anweisung, wenn eine Optimierung zum Kompilierungszeitpunkt angefordert wird. - Python 2 Docs Python 3 Docs

Wenn Sie assert verwenden, um Anwendungsfunktionalitäten zu implementieren und dann die Bereitstellung für die Produktion optimieren, werden Sie von "Aber-es-funktioniert-im-Dev-Modus" Problemen geplagt.

Siehe PYTHONOPTIMIZE und -O -OO

49 Stimmen

Wow! Super wichtige Bemerkung! Ich hatte geplant, asserts zu verwenden, um ein paar Dinge zu überprüfen, die niemals fehlschlagen sollten, deren Versagen darauf hinweisen würde, dass jemand sehr sorgfältig die Daten manipuliert hat, die sie senden, um Zugriff auf Daten zu erhalten, zu denen sie keinen Zugriff haben sollten. Es würde nicht funktionieren, aber ich möchte ihren Versuch schnell mit einem assert stoppen, daher würde es den Zweck vereiteln, wenn es in der Produktion optimiert würde. Ich denke, ich werde stattdessen einfach eine Exception auslösen. Oh - ich habe gerade eine passend benannte SuspiciousOperation Exception mit Unterklassen in Django entdeckt! Perfekt!

0 Stimmen

Übrigens, wenn Sie bandit auf Ihren Code ausführen, wird es Sie davor warnen.

0 Stimmen

@John Mee, danke für die wichtigen Informationen. Ich habe `assert` mit der Überprüfung der Python-Version verwendet, um sicherzustellen, dass es auf der erforderlichen Version korrekt ausgeführt wird. Aber `assert` funktioniert nicht für die Versionsüberprüfung im ausführbaren Python-Skript durch `#!/bin/python`. Jetzt habe ich den Grund aus deinen Informationen zu `assert` herausgefunden. Danke.

167voto

Nadia Alramli Punkte 105256

Um automatisch einen Fehler zu werfen, wenn x während der Funktion kleiner als null wird. Sie können Klassendeskriptoren verwenden. Hier ist ein Beispiel:

class LessThanZeroException(Exception):
    pass

class variable(object):
    def __init__(self, value=0):
        self.__x = value

    def __set__(self, obj, value):
        if value < 0:
            raise LessThanZeroException('x ist kleiner als null')

        self.__x  = value

    def __get__(self, obj, objType):
        return self.__x

class MyClass(object):
    x = variable()

>>> m = MyClass()
>>> m.x = 10
>>> m.x -= 20
Traceback (most recent call last):
  File "", line 1, in 
  File "my.py", line 7, in __set__
    raise LessThanZeroException('x ist kleiner als null')
LessThanZeroException: x ist kleiner als null

12 Stimmen

Obwohl Eigenschaften als Deskriptoren implementiert sind, würde ich das nicht als Beispiel für deren Verwendung bezeichnen. Dies ist vielmehr ein Beispiel für die Eigenschaften an und für sich: docs.python.org/library/functions.html#property

3 Stimmen

Die Eigenschaften sollten innerhalb von MyClass verwendet werden, wenn x eingestellt wird. Diese Lösung ist zu allgemein.

144 Stimmen

Ziemlich gute Antwort, mag ich, aber hat NICHTS mit der Frage zu tun... Können wir Deestans oder John Mees Antwort als gültige Antwort markieren?

164voto

Lutz Prechelt Punkte 32254

Die vier Zwecke von assert

Angenommen, Sie arbeiten an 200.000 Zeilen Code mit vier Kollegen Alice, Bernd, Carl und Daphne. Sie rufen Ihren Code auf, sie rufen Ihren Code auf.

Dann hat assert vier Aufgaben:

  1. Informieren Sie Alice, Bernd, Carl und Daphne darüber, was Ihr Code erwartet.
    Angenommen, Sie haben eine Methode, die eine Liste von Tupeln verarbeitet und die Programmlogik kann brechen, wenn diese Tupel nicht unveränderlich sind:

    def meineMethode(listeVonTupeln):
        assert(all(type(tp)==tuple for tp in listeVonTupeln))

    Dies ist verlässlicher als äquivalente Informationen in der Dokumentation und viel einfacher zu pflegen.

  2. Informieren Sie den Computer darüber, was Ihr Code erwartet.
    assert erzwingt korrektes Verhalten von den Aufrufern Ihres Codes. Wenn Ihr Code Alices und Bernds Code aufruft und Bernds Code Ihren aufruft, dann ohne das assert, wenn das Programm in Alices Code abstürzt, könnte Bernd annehmen, dass es Alices Schuld war, Alice untersucht und könnte davon ausgehen, dass es Ihre Schuld war, Sie untersuchen und sagen Bernd, dass es tatsächlich seine war. Viel Arbeit geht verloren.
    Mit asserts wird schnell klar, wer einen Aufruf falsch gemacht hat, sie werden schnell erkennen, dass es ihr Fehler war, nicht Ihrer. Alice, Bernd und Sie alle profitieren. Spart immense Mengen an Zeit.

  3. Informieren Sie die Leser Ihres Codes (einschließlich Ihnen selbst) darüber, was Ihr Code an einem bestimmten Punkt erreicht hat.
    Angenommen, Sie haben eine Liste von Einträgen und jeder von ihnen kann sauber sein (was gut ist) oder er kann smorsh, trale, gullup oder twinkled sein (was alles nicht akzeptabel ist). Wenn es smorsh ist, muss es unsmorshed sein; wenn es trale ist, muss es baludoed werden; wenn es gullup ist, muss es getrottet werden (und dann möglicherweise auch gepaced); wenn es twinkled ist, muss es noch einmal twinkled werden, außer an Donnerstagen. Sie verstehen: Es ist kompliziert. Aber das Endergebnis ist (oder sollte sein), dass alle Einträge sauber sind. Das Richtige(TM) ist, die Wirkung Ihrer Reinigungsschleife zusammenzufassen als

    assert(all(entry.isClean() for entry in meineListe))

    Diese Aussage erspart jedem eine Kopfschmerzen, der verstehen will, was genau die wunderbare Schleife erreicht. Und die häufigsten dieser Personen werden wahrscheinlich Sie selbst sein.

  4. Informieren Sie den Computer darüber, was Ihr Code an einem bestimmten Punkt erreicht hat.
    Sollten Sie jemals vergessen, einen Eintrag zu pacen, der nach dem Trotten benötigt wird, wird das assert Ihren Tag retten und verhindern, dass Ihr Code später Brüche bei der lieben Daphne verursacht.

In meinen Augen sind die beiden Zwecke von Dokumentation (1 und 3) und Schutz (2 und 4) von assert gleichermaßen wertvoll.
Die Information der Menschen kann sogar mehr wert sein als die Information des Computers, weil sie die Fehler verhindern kann, die das assert einfangen soll (im Fall von 1) und viele weitere Fehler in jedem Fall.

44 Stimmen

5. assert isinstance() hilft PyCharm (Python IDE) zu wissen, welcher Typ einer Variablen ist, es wird für die automatische Vervollständigung verwendet.

2 Stimmen

Stellt selbst dokumentierte Codeannahmen darüber dar, was zum aktuellen Ausführungszeitpunkt wahr ist. Es handelt sich um einen Annahmekommentar, der überprüft wird.

11 Stimmen

Bezüglich 2 und 4: Sie sollten sehr darauf achten, dass Ihre Asserts nicht zu streng sind. Andernfalls könnten die Asserts selbst das einzige sein, was verhindert, dass Ihr Programm in einem allgemeineren Umfeld verwendet werden kann. Insbesondere das Behaupten von Typen widerspricht Pythons Entenschnabel-Typisierung.

24voto

outis Punkte 71613

Zusätzlich zu den anderen Antworten werfen Assertions selbst Ausnahmen, aber nur AssertionError. Aus utilitaristischer Sicht sind Assertions nicht geeignet, wenn Sie eine feine Kontrolle darüber benötigen, welche Ausnahmen Sie abfangen.

3 Stimmen

Richtig. Es wäre sinnlos, Ausnahmefehler beim Aufrufer abzufangen.

1 Stimmen

Sehr guter Punkt. Eine Feinheit, die leicht übersehen werden kann, wenn man nur die Originalfragen auf Makroebene betrachtet. Selbst wenn es nicht das Problem mit den Ausführungen gäbe, die beim Optimieren fallen gelassen werden, würde das Verlieren der spezifischen Details, welche Art von Fehler aufgetreten ist, das Debuggen viel herausfordernder machen. Prost, Outis!

1 Stimmen

Deine Antwort kann so verstanden werden, dass du AssertionErrors abfangen möchtest, wenn es dir nichts ausmacht, grob zu sein. In Wirklichkeit solltest du sie jedoch nicht abfangen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X