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.

5voto

Lutz Prechelt Punkte 32254

Gibt es ein Leistungsproblem?

  • Bitte denken Sie daran: "Machen Sie es zuerst funktionstüchtig, bevor Sie es schnell machen".
    Ein sehr kleiner Prozentsatz eines Programms ist normalerweise für seine Geschwindigkeit relevant. Sie können immer ein assert entfernen oder vereinfachen, wenn es sich jemals als Leistungsproblem herausstellt - und die meisten werden es nie sein.

  • Seien Sie pragmatisch:
    Nehmen Sie an, Sie haben eine Methode, die eine nicht leere Liste von Tupeln verarbeitet und die Programmlogik zusammenbricht, wenn diese Tupel nicht unveränderlich sind. Sie sollten schreiben:

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

    Das ist wahrscheinlich in Ordnung, wenn Ihre Listen normalerweise zehn Einträge lang sind, aber es kann ein Problem werden, wenn sie eine Million Einträge enthalten. Aber anstatt diese wertvolle Überprüfung gänzlich zu verwerfen, könnten Sie sie einfach herabstufen auf

    def meineMethode(listeVonTupeln):
        assert(type(listeVonTupeln[0])==tuple)  # tatsächlich _alle_ müssen Tupel sein!

    was kostengünstig ist, aber wahrscheinlich trotzdem die meisten tatsächlichen Programmfehler abfangen wird.

3 Stimmen

Sollte sein assert(len(listOfTuples)==0 or type(listOfTyples[0])==tuple).

1 Stimmen

Nein, das sollte es nicht. Das wäre ein viel schwächerer Test, weil es nicht mehr die "nicht-leere" Eigenschaft überprüft, die der zweite assert überprüft. (Der erste nicht, obwohl es sollte.)

2 Stimmen

Der zweite assert überprüft die Nicht-Leer-Eigenschaft nicht explizit; es ist eher ein Nebeneffekt. Wenn es eine Ausnahme wegen der leeren Liste auslösen würde, würde die Person, die mit dem Code arbeitet (jemand anderes oder der Autor, ein Jahr nachdem er geschrieben wurde), darauf starren und versuchen herauszufinden, ob der assert wirklich dazu gedacht war, die leere Listen-Situation abzufangen, oder ob das ein Fehler im assert selbst ist. Außerdem sehe ich nicht, wie das Nicht-Überprüfen des leeren Falls "viel schwächer" ist, während das Überprüfen nur des ersten Elements "97% korrekt" ist.

3voto

akD Punkte 969

Ein Assert wird verwendet, um zu überprüfen -
1. die gültige Bedingung,
2. die gültige Anweisung,
3. die wahre Logik;
des Quellcodes. Anstatt das gesamte Projekt zu scheitern, gibt es einen Alarm, dass etwas in Ihrer Quelldatei nicht angemessen ist.

Im Beispiel 1, da die Variable 'str' nicht NULL ist. Daher wird kein Assert oder Ausnahme ausgelöst.

Beispiel 1:

#!/usr/bin/python

str = 'Hallo Python!'
strNull = 'String ist Null'

if __debug__:
    if not str: raise AssertionError(strNull)
print str

if __debug__:
    print 'Dateiname '.ljust(30,'.'),(__name__)
    print 'Dateipfad '.ljust(30,'.'),(__file__)

------------------------------------------------------

Ausgabe:
Hallo Python!
Dateiname ..................... Hallo
Dateipfad ..................... C:/Python\hallo.py

Im Beispiel 2 ist die Variable 'str' NULL. Daher wird der Benutzer durch die assert-Anweisung davor bewahrt, mit einem fehlerhaften Programm weiterzumachen.

Beispiel 2:

#!/usr/bin/python

str = ''
strNull = 'NULL String'

if __debug__:
    if not str: raise AssertionError(strNull)
print str

if __debug__:
    print 'Dateiname '.ljust(30,'.'),(__name__)
    print 'Dateipfad '.ljust(30,'.'),(__file__)

------------------------------------------------------

Ausgabe:
AssertionError: NULL String

Wenn wir den Debug-Modus nicht wollen und das Problem mit der Assert-Anweisung im Quellcode erkannt haben. Deaktivieren Sie die Optimierungsoption

python -O assertStatement.py
es wird nichts gedruckt

3voto

Dirk Herrmann Punkte 5051

Die Verwendung von assert und das Auslösen von Ausnahmen dienen beide der Kommunikation.

  • Assertions sind Aussagen über die Korrektheit des Codes, die sich an Entwickler richten: Eine Assertion im Code informiert die Leser des Codes über Bedingungen, die erfüllt sein müssen, damit der Code korrekt ist. Eine zur Laufzeit fehlschlagende Assertion informiert Entwickler darüber, dass im Code ein Fehler vorliegt, der behoben werden muss.

  • Ausnahmen sind Hinweise auf nicht-typische Situationen, die zur Laufzeit auftreten können, aber nicht vom vorliegenden Code gelöst werden können. Diese sind für den aufrufenden Code gedacht, um dort behandelt zu werden. Das Auftreten einer Ausnahme bedeutet nicht zwangsläufig, dass ein Fehler im Code vorliegt.

Beste Praxis

Daher, wenn du das Auftreten einer spezifischen Situation zur Laufzeit als Fehler betrachtest, über den du die Entwickler informieren möchtest ("Hallo Entwickler, diese Bedingung deutet darauf hin, dass irgendwo ein Fehler vorliegt, bitte korrigiere den Code."), dann verwende eine Assertion. Wenn die Assertion die Eingabeargumente deines Codes überprüft, solltest du in der Dokumentation typischerweise hinzufügen, dass dein Code ein "undefiniertes Verhalten" aufweist, wenn die Eingabeargumente gegen diese Bedingungen verstoßen.

Wenn das Auftreten dieser Situation hingegen in deinen Augen kein Anzeichen eines Fehlers ist, sondern eher eine (vielleicht seltene, aber) mögliche Situation, die stattdessen vom Client-Code behandelt werden sollte, löse eine Ausnahme aus. Die Situationen, in denen eine Ausnahme ausgelöst wird, sollten Bestandteil der Dokumentation des jeweiligen Codes sein.

Gibt es eine Leistungs [...] beeinträchtigung bei der Verwendung von assert

Die Auswertung von Assertions kostet Zeit. Sie können jedoch zur Kompilierzeit eliminiert werden. Dies hat jedoch einige Konsequenzen, siehe unten.

Gibt es ein [...] Wartungsproblem bei der Verwendung von assert

Normalerweise verbessern Assertions die Wartbarkeit des Codes, da sie die Lesbarkeit verbessern, indem sie Annahmen explizit machen und während der Laufzeit regelmäßig diese Annahmen überprüfen. Dies hilft auch dabei, Regressionen zu erkennen. Es gibt jedoch eine Sache, die beachtet werden muss: Ausdrücke, die in Assertions verwendet werden, sollten keine Seiteneffekte haben. Wie oben erwähnt, können Assertions zur Kompilierzeit eliminiert werden - was bedeutet, dass auch potenzielle Seiteneffekte verschwinden würden. Dies könnte - unbeabsichtigt - das Verhalten des Codes ändern.

0voto

denfromufa Punkte 5527

In Entwicklungsumgebungen wie PTVS, PyCharm, Wing assert isinstance() Anweisungen können verwendet werden, um Code-Vervollständigung für einige unklare Objekte zu ermöglichen.

0 Stimmen

Dies scheint vor der Verwendung von Typenannotationen oder von typing.cast zu liegen.

0 Stimmen

Cf Kommentare zu Lutz Prechtelts Antwort (dies wird oft nicht empfohlen, da Sie bessere Möglichkeiten haben, Typen wie Typhinweise zu spezifizieren)

0voto

Nephanth Punkte 441

Ich füge hinzu, dass ich oft assert verwende, um Eigenschaften wie Schleifeninvarianten oder logische Eigenschaften anzugeben, die mein Code haben sollte, ähnlich wie ich sie in formal verifizierter Software angebe.

Sie dienen sowohl dazu, die Leser zu informieren, mir beim Nachdenken zu helfen und zu überprüfen, ob ich keinen Fehler in meinem Denken mache. Zum Beispiel:

k = 0
for i in range(n):
    assert k == i * (i + 1) // 2
    k += i 
    #do some things      

oder in komplizierteren Situationen:

def sorted(l):
   return all(l1 <= l2 for l1, l2 in zip(l, l[1:]))

def mergesort(l):
   if len(l) < 2: #python 3.10 wird anstelle der Längenüberprüfung ein Match-Case haben
      return l
   k = len(l // 2)
   l1 = mergesort(l[:k])
   l2 = mergesort(l[k:])
   assert sorted(l1) # durch die asserts kann ich explizit angeben, welche Eigenschaften mein Code haben sollte
   assert sorted(l2) # Ich erwarte, dass sie in einem Produktionsbuild deaktiviert sind
   return merge(l1, l2)

Da die asserts deaktiviert sind, wenn Python im optimierten Modus ausgeführt wird, zögern Sie nicht, kostspielige Bedingungen in sie zu schreiben, insbesondere wenn dies Ihren Code klarer und weniger fehleranfällig macht

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