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.

19voto

Jason Baker Punkte 180981

Das einzige Problem an diesem Ansatz ist, dass es schwierig ist, eine sehr beschreibende Ausnahme mit assert-Anweisungen zu machen. Wenn Sie nach der einfacheren Syntax suchen, denken Sie daran, dass Sie auch etwas wie dies tun können:

class XLessThanZeroException(Exception):
    pass

def CheckX(x):
    if x < 0:
        raise XLessThanZeroException()

def foo(x):
    CheckX(x)
    # Hier etwas tun

Ein weiteres Problem ist, dass es schwierig ist, die Debugging-Asserts mit dem -O-Flag zu deaktivieren, wenn man assert für normale Bedingungsüberprüfungen verwendet.

28 Stimmen

Sie können einer Behauptung eine Fehlermeldung anfügen. Es ist der zweite Parameter. Das wird es beschreibend machen.

14voto

Das englische Wort assert wird hier im Sinne von schwören, bestätigen, bekräftigen verwendet. Es bedeutet nicht "überprüfen" oder "sollte sein". Es bedeutet, dass du als Programmierer hier eine eidliche Aussage machst:

# Ich schwöre feierlich, dass ich hier die Wahrheit, die ganze Wahrheit 
# und nichts als die Wahrheit sagen werde, unter Strafandrohung und Strafe, so wahr mir das FSM helfe
assert answer == 42

Wenn der Code korrekt ist, abgesehen von Single-Event-Störungen, Hardwarefehlern und ähnlichem, wird kein assert jemals fehlschlagen. Deshalb darf das Verhalten des Programms für den Endbenutzer nicht beeinträchtigt werden. Insbesondere darf ein assert selbst unter außergewöhnlichen programmatischen Bedingungen nicht fehlschlagen. Das passiert einfach nie. Wenn es passiert, sollte der Programmierer dafür gemaßregelt werden.

9voto

matts1 Punkte 797

Wie bereits erwähnt wurden, sollten Assertions verwendet werden, wenn Ihr Code NIEMALS einen bestimmten Punkt erreichen sollte, was bedeutet, dass dort ein Fehler vorliegt. Wahrscheinlich der nützlichste Grund, den ich sehe, um eine Assertion zu verwenden, ist eine Invariante/Vorbedingung/Nachbedingung. Diese müssen zu Beginn oder am Ende jeder Iteration einer Schleife oder einer Funktion wahr sein.

Zum Beispiel eine rekursive Funktion (2 separate Funktionen, damit eine schlechte Eingabe und die andere schlechter Code behandelt, da es schwer ist, mit Rekursion zu unterscheiden). Dadurch wäre offensichtlich, wenn ich vergessen hätte, die IF-Anweisung zu schreiben, was schief gelaufen ist.

def SumToN(n):
    if n <= 0:
        raise ValueError, "N muss größer oder gleich 0 sein"
    else:
        return RecursiveSum(n)

def RecursiveSum(n):
    #Vorbedingung: n >= 0
    assert(n >= 0)
    if n == 0:
        return 0
    return RecursiveSum(n - 1) + n
    #Nachbedingung: Summe von 1 bis n zurückgegeben

Diese Schleifeninvarianten können oft mit einer Assertion dargestellt werden.

3 Stimmen

Das wird am besten mit Dekoratoren (@Vorbedingung und @Nachbedingung) gemacht.

0 Stimmen

@Caridorc Was ist der konkrete Nutzen davon?

0 Stimmen

@ChieltenBrinke selbst dokumentierter Code, anstatt #Vorbedingung: n >= 0 und einem assert kann er einfach @Vorbedingung(lambda n: n >= 0) schreiben.

9voto

Emilio M Bumachar Punkte 2458

Für das, was es wert ist, wenn Sie es mit Code zu tun haben, der auf assert angewiesen ist, um ordnungsgemäß zu funktionieren, dann wird durch das Hinzufügen des folgenden Codes sichergestellt, dass die Anweisungen aktiviert sind:

try:
    assert False
    raise Exception('Python-Behauptungen funktionieren nicht. Dieses Tool basiert auf Python-Behauptungen, um seine Arbeit zu erledigen. Mögliche Ursachen sind das Ausführen mit dem "-O"-Flag oder das Ausführen eines vorkompilierten (".pyo" oder ".pyc")-Moduls.')
except AssertionError:
    pass

4 Stimmen

Das beantwortet nicht die Frage des Threaderstellers, die sich auf bewährte Verfahren bezieht.

7voto

Tomasz Gandor Punkte 7117

Gut, dies ist eine offene Frage, und ich möchte zwei Aspekte ansprechen: wann Assertions hinzuzufügen sind und wie man die Fehlermeldungen schreibt.

Zweck

Um es einem Anfänger zu erklären - Assertions sind Aussagen, die Fehler auslösen können, die jedoch nicht abgefangen werden. Und sie sollten normalerweise nicht ausgelöst werden, aber im wirklichen Leben passiert es manchmal trotzdem. Und dies ist eine ernste Situation, aus der der Code nicht wiederherstellen kann, was wir einen 'fatalen Fehler' nennen.

Als nächstes dienen sie 'zum Debuggen', was zwar korrekt ist, aber sehr herablassend klingt. Ich mag die Formulierung 'deklarieren von Invarianten, die niemals verletzt werden sollen' besser, obwohl sie bei verschiedenen Anfängern unterschiedlich funktioniert... Manche 'kapieren es einfach', und andere finden entweder keinen Nutzen dafür, ersetzen normale Ausnahmen oder sogar den Kontrollfluss damit.

Stil

In Python ist assert eine Anweisung, keine Funktion! (bedenke, dass assert(False, 'ist wahr') nicht ausgelöst wird. Aber, um das aus dem Weg zu räumen:

Wann und wie sollte die optionale 'Fehlermeldung' geschrieben werden?

Dies gilt tatsächlich für Unit-Test-Frameworks, die oft viele dedizierte Methoden für Assertions haben (assertTrue(Bedingung), assertFalse(Bedingung), assertEqual(aktuell, erwartet) usw.). Sie bieten oft auch eine Möglichkeit, die Assertion zu kommentieren.

In Wegwerfcode könnten Sie ohne die Fehlermeldungen auskommen.

In einigen Fällen gibt es nichts zur Assertion hinzuzufügen:

def dump(etwas): assert isinstance(etwas, Dumpable) # ...

Aber abgesehen davon ist eine Nachricht nützlich für die Kommunikation mit anderen Programmierern (die manchmal interaktive Benutzer Ihres Codes sind, z.B. in Ipython/Jupyter etc.).

Geben Sie ihnen Informationen, nicht nur interne Implementierungsdetails preis.

anstatt:

assert bedeutungsloser_identifier <= MAGIC_NUMBER_XXX, 'bedeutungsloser_identifier ist größer als MAGIC_NUMBER_XXX!!!'

schreiben Sie:

assert bedeutungsloser_identifier > MAGIC_NUMBER_XXX, 'Reaktortemperatur über kritischem Schwellenwert'

oder vielleicht sogar:

assert bedeutungsloser_identifier > MAGIC_NUMBER_XXX, f'Reaktortemperatur({bedeutungsloser_identifier }) über kritischem Schwellenwert ({MAGIC_NUMBER_XXX})'

Ich weiß, ich weiß - das ist kein Fall für eine statische Assertion, aber ich möchte auf den Informationswert der Nachricht hinweisen.

Negative oder positive Nachricht?

Dies mag umstritten sein, aber es tut mir weh, Dinge wie zu lesen:

assert a == b, 'a ist nicht gleich b'
  • dies sind zwei widersprüchliche Dinge, die nebeneinander geschrieben sind. Also wann immer ich Einfluss auf den Code habe, dränge ich darauf zu spezifizieren, was wir wollen, indem ich zusätzliche Verben wie 'muss' und 'sollte' verwende, und nicht zu sagen, was wir nicht wollen.

    assert a == b, 'a muss gleich b sein'

Dann ist AssertionError: a muss gleich b sein auch lesbar, und die Aussage sieht logisch im Code aus. Außerdem kann man daraus etwas ableiten, ohne den Traceback lesen zu müssen (der manchmal nicht einmal verfügbar ist).

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