Best Practice für Python Assert

483
  1. Gibt es ein Leistungs- oder Codewartungsproblem bei der Verwendung assertals 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'
  2. Gibt es auch eine Möglichkeit, eine solche Geschäftsregel festzulegen if x < 0 raise error, die immer ohne diese try/except/finallyOption überprüft wird ? Wenn der gesamte Code zu irgendeinem Zeitpunkt xkleiner als 0 ist, wird ein Fehler ausgelöst, wie wenn Sie ihn assert x < 0zu Beginn einer Funktion an einer beliebigen Stelle innerhalb der Funktion festlegen Wo xwird kleiner als 0, wird eine Ausnahme ausgelöst?

meade
quelle
3
Für die Aufzeichnung: mail.python.org/pipermail/python-list/2013-November/660401.html
Tomasz Zieliński
29
-O und -OO Python-Parameter entfernen Ihre Behauptungen. Das sollte Ihr Denken darüber anregen, wofür es gut ist.
Peter Lada
4
Der Link von Thomasz Zielinski wurde unterbrochen, jetzt: mail.python.org/pipermail/python-list/2013-November/660568.html . Ich bin mir ziemlich sicher, dass Pipermail eine instabile ID-Funktion hat. Ich habe andere Links innerhalb derselben Pipermail gefunden, die mit derselben Absicht auf dieselbe URL verweisen.
Quodlibetor
3
Falls mail.python.org/pipermail/python-list/2013-November/660568.html erneut verschoben wird, wird es unter archive.is/5GfiG archiviert . Der Titel des Beitrags lautet "Wann man Assert verwendet" und ist ein ausgezeichneter Beitrag (wirklich ein Artikel) zu Best Practices für Python assert.
Clacke

Antworten:

144

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:

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 is less than zero')

        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 "<stdin>", line 1, in <module>
  File "my.py", line 7, in __set__
    raise LessThanZeroException('x is less than zero')
LessThanZeroException: x is less than zero
Nadia Alramli
quelle
10
Obwohl Eigenschaften als Deskriptoren implementiert sind, würde ich dies nicht als Beispiel für ihre Verwendung bezeichnen. Dies ist eher ein Beispiel für Eigenschaften an und für sich: docs.python.org/library/functions.html#property
Jason Baker
3
Die Eigenschaften sollten in MyClass verwendet werden, wenn x festgelegt wird. Diese Lösung ist zu allgemein.
113
Ziemlich nette Antwort, mag es, hat aber NICHTS mit der Frage zu tun ... Können wir die Antwort von Deestan oder John Mee nicht als gültige Antwort markieren?
Vajk Hermecz
4
Dies scheint den Titel der Frage nicht zu beantworten. Dies ist auch eine schlechte Alternative zu Pythons Klasseneigenschaftsfunktion.
Dooms101
10
@VajkHermecz: Wenn Sie die Frage erneut lesen, sind dies zwei Fragen in einer. Personen, die nur den Titel betrachten, kennen nur die erste Frage, die diese Antwort nicht beantwortet. Diese Antwort enthält tatsächlich eine Antwort auf die zweite Frage.
ArtOfWarfare
742

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 dictfalsche Formatierung in der Datei a auslösen ConfigurationSyntaxError, solange Sie können, assertdass Sie nicht zurückkehren werden None.


In Ihrem Beispiel xist eine Ausnahme am besten , wenn ein Wert über eine Benutzeroberfläche oder von einer externen Quelle festgelegt wurde.

Wenn dies xnur durch Ihren eigenen Code im selben Programm festgelegt wird, gehen Sie mit einer Zusicherung vor.

Deestan
quelle
126
Dies ist der richtige Weg, um Asserts zu verwenden. Sie sollten nicht zur Steuerung des Programmflusses verwendet werden.
Thane Brimhall
41
+1 für den letzten Absatz - obwohl Sie ausdrücklich erwähnen sollten, dass er assertein implizites enthält if __debug__und möglicherweise wegoptimiert wird - wie John Mees Antwort besagt
Tobias Kienzler
3
Erneutes Lesen Ihrer Antwort Ich denke, Sie haben wahrscheinlich nicht Bedingungen gemeint, die in der Regel niemals gemeint sein sollten, sondern der Zweck besteht darin, im Falle eines beschädigten Programmzustands, der normalerweise mit einer Bedingung zusammenfällt, die Sie nicht erwarten, frühzeitig abzustürzen jemals passieren .
Bentley4
10
assert sollte nur verwendet werden, um Probleme ohne bekannte Wiederherstellung zu erkennen. fast immer Codefehler (keine schlechten Eingaben). Wenn eine Bestätigung ausgelöst wird, sollte dies bedeuten, dass sich das Programm in einem Zustand befindet, in dem es möglicherweise gefährlich ist, fortzufahren, da es möglicherweise mit dem Netzwerk kommuniziert oder auf die Festplatte schreibt. Robuster Code wechselt angesichts fehlerhafter (oder böswilliger) Eingaben "atomar" vom gültigen Status in den gültigen Status. Die oberste Ebene jedes Threads sollte eine Fehlersperre aufweisen. Fehlerbarrieren, die Eingaben von der Außenwelt verbrauchen, schlagen im Allgemeinen nur für eine Iteration der Barriere (while / try) fehl, Rollback- / Anmeldefehler.
Rob
10
"Asserts sollten verwendet werden, um Bedingungen zu testen, die niemals eintreten sollten." Ja. Und die Bedeutung des zweiten "sollte" ist: Wenn dies passiert, ist der Programmcode falsch.
Lutz Prechelt
362

"assert" -Anweisungen werden entfernt, wenn die Kompilierung optimiert wird . Ja, es gibt sowohl Leistungs- als auch Funktionsunterschiede.

Der aktuelle Codegenerator gibt keinen Code für eine Assert-Anweisung aus, wenn zur Kompilierungszeit eine Optimierung angefordert wird. - Python 2-Dokumente Python 3-Dokumente

Wenn Sie Anwendungsfunktionen assertimplementieren und dann die Bereitstellung für die Produktion optimieren, werden Sie von "but-it-works-in-dev" -Fehlern geplagt.

Siehe PYTHONOPTIMIZE und -O -OO

John Mee
quelle
26
Beeindruckend! Super wichtiger Hinweis also! Ich hatte geplant, Asserts zu verwenden, um einige Dinge zu überprüfen, die niemals fehlschlagen sollten. Ihr Fehler würde darauf hinweisen, dass jemand meine gesendeten Daten sehr sorgfältig manipulierte, um Zugriff auf Daten zu erhalten, auf die er keinen Zugriff haben sollte. Es würde nicht funktionieren, aber ich möchte ihren Versuch mit einer Behauptung schnell beenden, so dass eine Optimierung in der Produktion den Zweck zunichte machen würde. Ich denke, ich werde stattdessen nur raiseeine Exception. Oh - ich habe gerade einen treffenden Namen SuspiciousOperation Exceptionmit Unterklassen entdeckt Django! Perfekt!
ArtOfWarfare
Übrigens, @ArtOfWarfare, wenn Sie banditIhren Code ausführen, wird Sie davor gewarnt.
Nagev
132

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 asserthat vier Rollen :

  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 unterbrochen werden, wenn diese Tupel nicht unveränderlich sind:

    def mymethod(listOfTuples):
        assert(all(type(tp)==tuple for tp in listOfTuples))

    Dies ist vertrauenswürdiger als gleichwertige Informationen in der Dokumentation und viel einfacher zu pflegen.

  2. Informieren Sie den Computer darüber, was Ihr Code erwartet.
    assertErzwingt das ordnungsgemäße Verhalten der Aufrufer Ihres Codes. Wenn Ihr Code Alices und Bernds Code Ihren aufruft, dann assertkö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.

  3. 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

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

    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.

  4. 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, assertwird dies Ihren Tag retten und vermeiden, dass Ihr Code viel später den lieben Daphne bricht.

Meiner Meinung nach sind assertdie 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 , assertZiele zu fangen (im Fall 1) und vielen nachfolgenden Fehler in jedem Fall.

Lutz Prechelt
quelle
34
5. Assert isinstance () hilft PyCharm (Python IDE), den Variablentyp zu kennen. Er wird für die automatische Vervollständigung verwendet.
Cjkjvfnby
1
Aktiviert Annahmen zum Selbstdokumentcode für das, was zum aktuellen Ausführungszeitpunkt wahr ist. Es ist ein Annahmekommentar, der überprüft wird.
Pyj
9
Zu 2 und 4: Sie sollten sehr vorsichtig sein, dass Ihre Behauptungen nicht zu streng sind. Andernfalls sind die Behauptungen selbst möglicherweise das einzige, was Ihr Programm in einer allgemeineren Umgebung verwendet. Besonders die Behauptung von Typen widerspricht der Ententypisierung von Python.
zwirbeltier
9
@Cjkjvfnby Seien Sie vorsichtig bei einer Überbeanspruchung von isinstance (), wie in diesem Blogeintrag beschrieben: " isinstance () gilt als schädlich ". Sie können jetzt Dokumentzeichenfolgen verwenden, um Typen in Pycharm anzugeben .
Binarysubstrate
2
Verwenden von Asserts auf eine Weise, um den Vertrag sicherzustellen. Weitere Informationen zu Design by Contract en.wikipedia.org/wiki/Design_by_contract
Leszek Zarna
22

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.

outis
quelle
3
Recht. Es erscheint unsinnig, Assertionsfehlerausnahmen im Aufrufer abzufangen.
Raffi Khatchadourian
Sehr guter Punkt. Eine Nuance, die leicht übersehen werden kann, wenn man nur die ursprünglichen Fragen auf Makroebene betrachtet. Selbst wenn es nicht das Problem gäbe, dass Zusicherungen bei der Optimierung gelöscht werden, würde das Verlieren der spezifischen Details darüber, welche Art von Fehler aufgetreten ist, das Debuggen viel schwieriger machen. Prost, outis!
cfwschmidt
Ihre Antwort kann so gelesen werden, als ob Sie sie fangen möchten AssertionErrors, wenn Sie damit einverstanden sind, dass sie grobkörnig ist. In Wirklichkeit sollten Sie sie nicht fangen.
Tomasz Gandor
19

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:

class XLessThanZeroException(Exception):
    pass

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

def foo(x):
    CheckX(x)
    #do stuff here

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.

Jason Baker
quelle
24
Sie können eine Fehlermeldung an eine Zusicherung anhängen. Es ist der zweite Parameter. Das wird es beschreibend machen.
Raffi Khatchadourian
10

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:

# I solemnly swear that here I will tell the truth, the whole truth, 
# and nothing but the truth, under pains and penalties of perjury, so help me FSM
assert answer == 42

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.

Antti Haapala
quelle
8

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.

def SumToN(n):
    if n <= 0:
        raise ValueError, "N must be greater than or equal to 0"
    else:
        return RecursiveSum(n)

def RecursiveSum(n):
    #precondition: n >= 0
    assert(n >= 0)
    if n == 0:
        return 0
    return RecursiveSum(n - 1) + n
    #postcondition: returned sum of 1 to n

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

matts1
quelle
2
Dies geschieht am besten mit Dekorateuren (@precondition und @postcondition)
Caridorc
@Caridorc was ist der konkrete Vorteil davon?
Chiel zehn Brinke
@ChaltenBrinke selbstdokumentierenden Code, anstatt #precondition: n >= 0 und eine Behauptung, kann er einfach schreiben@precondition(lambda n: n >= 0)
Caridorc
@Caridorc Sind das dann eingebaute Dekorateure? Und wie generiert man daraus eine Dokumentation?
Chiel zehn Brinke
@ChaltenBrinke nicht integriert, aber einfach zu implementieren stackoverflow.com/questions/12151182/… . Für die Dokumentation patchen Sie einfach das __doc__Attribut, indem Sie eine zusätzliche Zeichenfolge
angeben
4

Gibt 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 assertein 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:

    def mymethod(listOfTuples):
        assert(all(type(tp)==tuple for tp in listOfTuples))

    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

    def mymethod(listOfTuples):
        assert(type(listOfTuples[0])==tuple)  # in fact _all_ must be tuples!

    was billig ist , aber wahrscheinlich die meisten der Fang tatsächlichen Programmfehler sowieso.

Lutz Prechelt
quelle
2
Sollte sein assert(len(listOfTuples)==0 or type(listOfTyples[0])==tuple).
osa
Nein, sollte es nicht. Dies wäre ein viel schwächerer Test, da die Eigenschaft "nicht leer", die mit der zweiten Bestätigung überprüft wird, nicht mehr überprüft wird. (Der erste nicht, obwohl es sollte.)
Lutz Prechelt
1
Die zweite Zusicherung überprüft die nicht leere Eigenschaft nicht explizit. Es ist eher ein Nebeneffekt. Wenn es eine Ausnahme geben würde, weil die Liste leer ist, würde die Person, die mit dem Code arbeitet (jemand anderes oder der Autor, ein Jahr nach dem Schreiben), darauf starren und versuchen herauszufinden, ob die Behauptung wirklich zum Fangen gedacht war die leere Listensituation, oder wenn das ein Fehler in der Behauptung selbst ist. Außerdem sehe ich nicht, dass es "viel schwächer" ist, nicht nach dem leeren Fall zu suchen, während nur das erste Element "97% korrekt" ist.
osa
3

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 assertist 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:

assert meaningless_identifier <= MAGIC_NUMBER_XXX, 'meaningless_identifier is greater than MAGIC_NUMBER_XXX!!!'

schreiben:

assert meaningless_identifier > MAGIC_NUMBER_XXX, 'reactor temperature above critical threshold'

oder vielleicht sogar:

assert meaningless_identifier > MAGIC_NUMBER_XXX, f'reactor temperature({meaningless_identifier }) above critical threshold ({MAGIC_NUMBER_XXX})'

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:

assert a == b, 'a is not equal to b'
  • 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 bauch 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).

Tomasz Gandor
quelle
1

Sowohl bei der Verwendung assertals 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.

Beste Übung

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.

Gibt es ein [...] Leistungsproblem bei der Verwendung? assert

Die Bewertung von Behauptungen dauert einige Zeit. Sie können jedoch zur Kompilierungszeit entfernt werden. Dies hat jedoch einige Konsequenzen, siehe unten.

Gibt es ein [...] Code-Wartungsproblem bei der Verwendung? assert

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.

Dirk Herrmann
quelle
1

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:

#!/usr/bin/python

str = 'hello Python!'
strNull = 'string is Null'

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

if __debug__:
    print 'FileName '.ljust(30,'.'),(__name__)
    print 'FilePath '.ljust(30,'.'),(__file__)


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

Output:
hello Python!
FileName ..................... hello
FilePath ..................... C:/Python\hello.py

In Beispiel 2 ist var 'str' null. Wir ersparen dem Benutzer also, fehlerhafte Programme durch assert- Anweisungen zu bearbeiten .

Beispiel 2:

#!/usr/bin/python

str = ''
strNull = 'NULL String'

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

if __debug__:
    print 'FileName '.ljust(30,'.'),(__name__)
    print 'FilePath '.ljust(30,'.'),(__file__)


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

Output:
AssertionError: NULL String

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

akD
quelle
0

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.

denfromufa
quelle
Dies scheint vor der Verwendung von Typanmerkungen oder von zu liegen typing.cast.
Acumenus
-1

Wenn Sie mit Code arbeiten, dessen assertordnungsgemäße Funktion erforderlich ist, wird durch Hinzufügen des folgenden Codes sichergestellt, dass Asserts aktiviert sind:

try:
    assert False
    raise Exception('Python assertions are not working. This tool relies on Python assertions to do its job. Possible causes are running with the "-O" flag or running a precompiled (".pyo" or ".pyc") module.')
except AssertionError:
    pass
Emilio M Bumachar
quelle
2
Dies beantwortet nicht die Frage von OP, die sich mit Best Practices befasst.
Codeforester