Gibt es ein Leistungs- oder Codewartungsproblem bei der Verwendung
assert
als Teil des Standardcodes, anstatt ihn nur für Debugging-Zwecke zu verwenden?Ist
assert x >= 0, 'x is less than zero'
besser oder schlechter als
if x < 0: raise Exception, 'x is less than zero'
Gibt es auch eine Möglichkeit, eine solche Geschäftsregel festzulegen
if x < 0 raise error
, die immer ohne diesetry/except/finally
Option überprüft wird ? Wenn der gesamte Code zu irgendeinem Zeitpunktx
kleiner als 0 ist, wird ein Fehler ausgelöst, wie wenn Sie ihnassert x < 0
zu Beginn einer Funktion an einer beliebigen Stelle innerhalb der Funktion festlegen Wox
wird kleiner als 0, wird eine Ausnahme ausgelöst?
483
assert
.Antworten:
Um automatisch einen Fehler auslösen zu können, wenn x während der gesamten Funktion kleiner als Null wird. Sie können Klassendeskriptoren verwenden . Hier ist ein Beispiel:
quelle
Asserts sollten verwendet werden, um Bedingungen zu testen, die niemals eintreten sollten . Der Zweck besteht darin, bei einem beschädigten Programmstatus frühzeitig abzustürzen.
Ausnahmen sollten für Fehler verwendet werden, die möglicherweise auftreten können, und Sie sollten fast immer Ihre eigenen Ausnahmeklassen erstellen .
Wenn Sie beispielsweise eine Funktion zum Lesen aus einer Konfigurationsdatei in eine schreiben, sollte eine
dict
falsche Formatierung in der Datei a auslösenConfigurationSyntaxError
, solange Sie können,assert
dass Sie nicht zurückkehren werdenNone
.In Ihrem Beispiel
x
ist eine Ausnahme am besten , wenn ein Wert über eine Benutzeroberfläche oder von einer externen Quelle festgelegt wurde.Wenn dies
x
nur durch Ihren eigenen Code im selben Programm festgelegt wird, gehen Sie mit einer Zusicherung vor.quelle
assert
ein implizites enthältif __debug__
und möglicherweise wegoptimiert wird - wie John Mees Antwort besagt"assert" -Anweisungen werden entfernt, wenn die Kompilierung optimiert wird . Ja, es gibt sowohl Leistungs- als auch Funktionsunterschiede.
Wenn Sie Anwendungsfunktionen
assert
implementieren und dann die Bereitstellung für die Produktion optimieren, werden Sie von "but-it-works-in-dev" -Fehlern geplagt.Siehe PYTHONOPTIMIZE und -O -OO
quelle
raise
eineException
. Oh - ich habe gerade einen treffenden NamenSuspiciousOperation
Exception
mit Unterklassen entdecktDjango
! Perfekt!bandit
Ihren Code ausführen, wird Sie davor gewarnt.Die vier Zwecke von
assert
Angenommen, Sie arbeiten mit vier Kollegen, Alice, Bernd, Carl und Daphne, an 200.000 Codezeilen. Sie nennen Ihren Code, Sie nennen ihren Code.
Dann
assert
hat vier Rollen :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 unterbrochen werden, wenn diese Tupel nicht unveränderlich sind:
Dies ist vertrauenswürdiger als gleichwertige Informationen in der Dokumentation und viel einfacher zu pflegen.
Informieren Sie den Computer darüber, was Ihr Code erwartet.
assert
Erzwingt das ordnungsgemäße Verhalten der Aufrufer Ihres Codes. Wenn Ihr Code Alices und Bernds Code Ihren aufruft, dannassert
könnte Bernd ohne das , wenn das Programm im Alices-Code abstürzt, annehmen, dass es Alices Schuld war, Alice untersucht und annehmen, dass es Ihre Schuld war, Sie untersuchen und sagen Bernd, dass es tatsächlich war seine. Viel Arbeit verloren.Mit Behauptungen kann jeder, der einen falschen Anruf erhält, schnell erkennen, dass es seine Schuld war, nicht Ihre. Alice, Bernd und Sie alle profitieren davon. Spart immense Zeit.
Informieren Sie die Leser Ihres Codes (einschließlich Ihrer selbst) darüber, was Ihr Code irgendwann erreicht hat.
Angenommen, Sie haben eine Liste mit Einträgen, von denen jeder sauber (was gut ist) oder smorsh, trale, gullup oder funkeln kann (was nicht akzeptabel ist). Wenn es smorsh ist, muss es unsmorshed sein; wenn es trale ist, muss es baludoed sein; Wenn es Gullup ist, muss es getrottet werden (und dann möglicherweise auch auf und ab gehen). Wenn es funkelt, muss es außer donnerstags erneut funkeln. Sie bekommen die Idee: Es ist kompliziertes Zeug. Das Endergebnis ist (oder sollte sein), dass alle Einträge sauber sind. Das Richtige ist, die Wirkung Ihrer Reinigungsschleife als zusammenzufassen
Diese Aussage erspart jedem Kopfschmerzen, der zu verstehen versucht, was genau die wunderbare Schleife erreicht. Und die häufigste dieser Personen wird wahrscheinlich Sie selbst sein.
Informieren Sie den Computer, was Ihr Code irgendwann erreicht hat.
Sollten Sie jemals vergessen, einen Eintrag zu beschleunigen, der nach dem Trab benötigt wird,
assert
wird dies Ihren Tag retten und vermeiden, dass Ihr Code viel später den lieben Daphne bricht.Meiner Meinung nach sind
assert
die beiden Zwecke der Dokumentation (1 und 3) und des Schutzes (2 und 4) gleichermaßen wertvoll.Kann die Menschen zu informieren , auch sein mehr wert als den Computer zu informieren , weil es die sehr Fehler , die verhindern kann ,
assert
Ziele zu fangen (im Fall 1) und vielen nachfolgenden Fehler in jedem Fall.quelle
Zusätzlich zu den anderen Antworten werfen Asserts selbst Ausnahmen aus, aber nur AssertionErrors. Aus utilitaristischer Sicht sind Behauptungen nicht geeignet, wenn Sie eine genaue Kontrolle darüber benötigen, welche Ausnahmen Sie abfangen.
quelle
AssertionErrors
, wenn Sie damit einverstanden sind, dass sie grobkörnig ist. In Wirklichkeit sollten Sie sie nicht fangen.Das einzige, was bei diesem Ansatz wirklich falsch ist, ist, dass es schwierig ist, mit assert-Anweisungen eine sehr beschreibende Ausnahme zu machen. Wenn Sie sich für die einfachere Syntax suchen, erinnern Sie können auch etwas tun:
Ein weiteres Problem besteht darin, dass die Verwendung von assert für die normale Zustandsprüfung es schwierig macht, die Debugging-Asserts mit dem Flag -O zu deaktivieren.
quelle
Das englischsprachige Wort assert wird hier im Sinne von schwören , bestätigen , bekennen verwendet . Es bedeutet nicht "überprüfen" oder "sollte sein" . Dies bedeutet, dass Sie als Programmierer hier eine eidesstattliche Erklärung abgeben:
Wenn der Code korrekt ist , wird kein Assert jemals fehlschlagen, es sei denn, es treten Störungen mit einem Ereignis , Hardwarefehler usw. auf . Deshalb darf das Verhalten des Programms gegenüber einem Endbenutzer nicht beeinflusst werden. Insbesondere kann eine Behauptung auch unter außergewöhnlichen programmatischen Bedingungen nicht scheitern . Es passiert einfach nie. In diesem Fall sollte der Programmierer dafür gezappt werden.
quelle
Wie bereits erwähnt, sollten Zusicherungen verwendet werden, wenn Ihr Code niemals einen Punkt erreichen sollte, was bedeutet, dass dort ein Fehler vorliegt. Der wahrscheinlich nützlichste Grund, warum ich eine Behauptung verwenden kann, ist eine Invariante / Vor- / Nachbedingung. Dies muss zu Beginn oder am Ende jeder Iteration einer Schleife oder einer Funktion zutreffen.
Zum Beispiel eine rekursive Funktion (2 separate Funktionen, so dass 1 fehlerhafte Eingaben und die andere fehlerhaften Code behandelt, da es schwierig ist, mit Rekursion zu unterscheiden). Dies würde deutlich machen, wenn ich vergessen hätte, die if-Anweisung zu schreiben, was schief gelaufen war.
Diese Schleifeninvarianten können oft mit einer Behauptung dargestellt werden.
quelle
#precondition: n >= 0
und eine Behauptung, kann er einfach schreiben@precondition(lambda n: n >= 0)
__doc__
Attribut, indem Sie eine zusätzliche ZeichenfolgeGibt es ein Leistungsproblem?
Bitte denken Sie daran, "es zuerst zum Laufen zu bringen, bevor Sie es schnell zum Laufen bringen" .
Sehr wenige Prozent eines Programms sind normalerweise für seine Geschwindigkeit relevant. Sie können
assert
ein Problem jederzeit lösen oder vereinfachen, wenn es sich jemals als Leistungsproblem herausstellt - und die meisten von ihnen werden es niemals tun.Seien Sie pragmatisch :
Angenommen, Sie haben eine Methode, die eine nicht leere Liste von Tupeln verarbeitet, und die Programmlogik wird unterbrochen, wenn diese Tupel nicht unveränderlich sind. Sie sollten schreiben:
Dies ist wahrscheinlich in Ordnung, wenn Ihre Listen in der Regel zehn Einträge lang sind. Wenn sie jedoch eine Million Einträge enthalten, kann dies zu einem Problem werden. Aber anstatt diesen wertvollen Scheck vollständig zu verwerfen, können Sie ihn einfach auf herabstufen
was billig ist , aber wahrscheinlich die meisten der Fang tatsächlichen Programmfehler sowieso.
quelle
assert(len(listOfTuples)==0 or type(listOfTyples[0])==tuple)
.Nun, dies ist eine offene Frage, und ich möchte zwei Aspekte ansprechen: wann ich Zusicherungen hinzufügen und wie ich die Fehlermeldungen schreibe.
Zweck
Um es einem Anfänger zu erklären - Behauptungen sind Aussagen, die Fehler verursachen können, aber Sie werden sie nicht fangen. Und normalerweise sollten sie nicht erzogen werden, aber im wirklichen Leben werden sie manchmal trotzdem erzogen. Und dies ist eine ernste Situation, die der Code nicht wiederherstellen kann, was wir als "schwerwiegenden Fehler" bezeichnen.
Als nächstes dient es 'Debugging-Zwecken', was, obwohl es korrekt ist, sehr abweisend klingt. Ich mag die Formulierung "Invarianten deklarieren, die niemals verletzt werden sollten" besser, obwohl sie bei verschiedenen Anfängern unterschiedlich funktioniert ... Einige "verstehen es einfach", andere finden entweder keine Verwendung dafür oder ersetzen normale Ausnahmen. oder sogar den Fluss damit steuern.
Stil
In Python
assert
ist eine Anweisung keine Funktion! (Denken Sie daran,assert(False, 'is true')
wird nicht erhöhen. Aber das aus dem Weg haben:Wann und wie wird die optionale 'Fehlermeldung' geschrieben?
Dies gilt acually zu Einheit Test - Frameworks, die oft viele engagierte Methoden zu tun haben Behauptungen (
assertTrue(condition)
,assertFalse(condition), assertEqual(actual, expected)
etc.). Sie bieten häufig auch die Möglichkeit, die Behauptung zu kommentieren.Im Wegwerfcode könnten Sie auf die Fehlermeldungen verzichten.
In einigen Fällen kann der Behauptung nichts hinzugefügt werden:
def dump (etwas): isinstance (etwas, Dumpable) behaupten # ...
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 usw.).
Geben Sie ihnen Informationen und nicht nur interne Implementierungsdetails.
anstatt:
schreiben:
oder vielleicht sogar:
Ich weiß, ich weiß - dies ist kein Fall für eine statische Behauptung, aber ich möchte auf den Informationswert der Nachricht verweisen.
Negative oder positive Nachricht?
Das mag umstritten sein, aber es tut mir weh, Dinge zu lesen wie:
Dies sind zwei widersprüchliche Dinge, die nebeneinander geschrieben sind. Wenn ich also Einfluss auf die Codebasis habe, dränge ich darauf, anzugeben, was wir wollen, indem ich zusätzliche Verben wie "muss" und "sollte" verwende und nicht sage, was wir nicht wollen.
behaupten a == b, 'a muss gleich b sein'
Dann ist das Abrufen
AssertionError: a must be equal to b
auch lesbar, und die Anweisung sieht im Code logisch aus. Sie können auch etwas daraus machen, ohne den Traceback zu lesen (der manchmal nicht einmal verfügbar ist).quelle
Sowohl bei der Verwendung
assert
als auch bei der Auslösung von Ausnahmen geht es um Kommunikation.Aussagen sind Aussagen über die Richtigkeit des Codes, die an Entwickler gerichtet sind : Eine Aussage im Code informiert die Leser des Codes über Bedingungen, die erfüllt sein müssen, damit der Code korrekt ist. Eine Behauptung, die zur Laufzeit fehlschlägt, informiert Entwickler darüber, dass der Code einen Fehler aufweist, der behoben werden muss.
Ausnahmen sind Hinweise auf nicht typische Situationen, die zur Laufzeit auftreten können, aber nicht durch den vorliegenden Code behoben werden können, der an den dort zu behandelnden aufrufenden Code adressiert ist. Das Auftreten einer Ausnahme zeigt nicht an, dass der Code einen Fehler enthält.
Wenn Sie daher das Auftreten einer bestimmten Situation zur Laufzeit als Fehler betrachten, über den Sie die Entwickler informieren möchten ("Hallo Entwickler, diese Bedingung weist darauf hin, dass irgendwo ein Fehler vorliegt, beheben Sie bitte den Code.") eine Behauptung aufstellen. Wenn die Zusicherung Eingabeargumente Ihres Codes überprüft, sollten Sie der Dokumentation normalerweise hinzufügen, dass Ihr Code "undefiniertes Verhalten" aufweist, wenn die Eingabeargumente gegen diese Bedingungen verstoßen.
Wenn stattdessen das Auftreten dieser Situation kein Hinweis auf einen Fehler in Ihren Augen ist, sondern eine (möglicherweise seltene, aber) mögliche Situation, die Ihrer Meinung nach eher vom Client-Code behandelt werden sollte, lösen Sie eine Ausnahme aus. Die Situationen, in denen eine Ausnahme ausgelöst wird, sollten Teil der Dokumentation des jeweiligen Codes sein.
Die Bewertung von Behauptungen dauert einige Zeit. Sie können jedoch zur Kompilierungszeit entfernt werden. Dies hat jedoch einige Konsequenzen, siehe unten.
Normalerweise verbessern Zusicherungen die Wartbarkeit des Codes, da sie die Lesbarkeit verbessern, indem sie Annahmen explizit machen und diese Annahmen zur Laufzeit regelmäßig überprüfen. Dies wird auch dazu beitragen, Regressionen zu fangen. Es gibt jedoch ein Problem, das berücksichtigt werden muss: Ausdrücke, die in Behauptungen verwendet werden, sollten keine Nebenwirkungen haben. Wie oben erwähnt, können Behauptungen zur Kompilierungszeit eliminiert werden - was bedeutet, dass auch die möglichen Nebenwirkungen verschwinden würden. Dies kann - unbeabsichtigt - das Verhalten des Codes ändern.
quelle
Eine Behauptung besteht darin, Folgendes 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, wird ein Alarm ausgegeben, dass etwas in Ihrer Quelldatei nicht angemessen ist.
In Beispiel 1 ist die Variable 'str' nicht null. Es werden also keine Behauptungen oder Ausnahmen ausgelöst.
Beispiel 1:
In Beispiel 2 ist var 'str' null. Wir ersparen dem Benutzer also, fehlerhafte Programme durch assert- Anweisungen zu bearbeiten .
Beispiel 2:
In dem Moment wollen wir kein Debugging und haben das Assertion-Problem im Quellcode erkannt. Deaktivieren Sie das Optimierungsflag
python -O assertStatement.py
nichts wird gedruckt
quelle
In IDEs wie PTVS, PyCharm und Wing können
assert isinstance()
Anweisungen verwendet werden, um die Code-Vervollständigung für einige unklare Objekte zu ermöglichen.quelle
typing.cast
.Wenn Sie mit Code arbeiten, dessen
assert
ordnungsgemäße Funktion erforderlich ist, wird durch Hinzufügen des folgenden Codes sichergestellt, dass Asserts aktiviert sind:quelle