`assert` - warum?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Mittwoch 27. Dezember 2006, 17:51

http://de.wikipedia.org/wiki/Assert

Hab eine Frage. Warum assert? Ist es nicht besser stattdessen eine "richtige" Exception auszulösen? Hab den oberen Artikel gelesen und soweit verstanden bloß frage ich mich nun wann assert angebracht ist und ob man das nicht zu oft benutzen sollte.

lg
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Mittwoch 27. Dezember 2006, 19:40

sape hat geschrieben:Warum assert?
Hi sape!

``assert`` meldet mir meine eigenen persönlichen Fehler, die ich so beim Programmieren mache.

``assert`` hindert mich z.B. daran, die Zahl 100 zu übergeben, wenn ich nur eine Zahl zwischen 1 und 99 übergeben darf.

Viele dieser Prüfungen sind beim Programmieren noch recht wichtig, aber im fertigen Programm meist nicht mehr so sinnvoll. Ob jetzt der übergebene Parameter auch wirklich die eine oder andere Eigenschaft hat, ist für mich beim Programmieren wichtig. So merke ich frühzeitig, wenn ich etwas falsches übergebe.

``assert`` hat mich schon oft auf Fehler bei der Parameterübergabe aufmerksam gemacht. Deshalb setze ich es oft ein wenn die Qualität des Quellcodes sehr hoch sein muss und ich Fehler im Quellcode ziemlich früh bemerken möchte. Jetzt könnte man das typische DuckTyping-Argument nennen, aber ich denke, man muss immer abwiegen und selber entscheiden, ob eine eher lockere DuckTyping-Prüfung oder ein striktes ``isinstance`` angebracht ist.

``assert`` wird nicht ausgeführt, wenn Python mit ``-O`` gestartet wird. Man sollte aber auch im Hinterkopf behalten, dass die meisten Python-Programme NICHT mit ``-O`` ausgeführt werden.

Wenn man irgendwann alle ``assert``-Anweisungen los werden will, dann ist das mit einem Editor, der suchen kann, in wenigen Minuten erledigt.

``assert`` hat noch einen Vorteil: :D Man unterstützt dadurch die Code-Vervollständigung von WingIDE. Wenn WingIDE mal nicht weiß, was für ein Datentyp vorliegt und deshalb auch keine Code-Vervollständigung anbieten kann, dann hilft man einfach mit einem ``assert(isinstance())`` nach. Schon kann einem WingIDE beim Programmieren weiter helfen.

Fazit: ``assert`` hilft mir beim Programmieren Fehler zu vermeiden. ``assert`` ist nicht dazu gedacht, Benutzerfehler abzufangen.

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
BlackJack

Mittwoch 27. Dezember 2006, 20:30

sape hat geschrieben:http://de.wikipedia.org/wiki/Assert

Hab eine Frage. Warum assert? Ist es nicht besser stattdessen eine "richtige" Exception auszulösen? Hab den oberen Artikel gelesen und soweit verstanden bloß frage ich mich nun wann assert angebracht ist und ob man das nicht zu oft benutzen sollte.
Mit `assert` testet man auf Sachen die unmöglich passieren können. Fehler in eigenem Quelltext, zum Beispiel Nachbedingungen oder Invarianten wie in dem Text ja auch beschrieben wird. Und es gibt auch keine sinnvolle Reaktion auf eine fehlgeschlagene Zusicherung. Man soll ja niemals nie sagen, aber `AssertionError` zu behandeln, ausser vielleicht um ein Errorlog oder so zu erstellen, ist ziemlich "falsch".

Beispiele:

In einem RLE-Packer der Daten für den C64 komprimiert:

Code: Alles auswählen

                    if self._runCount > 255:
                        assert self._runCount < 0x10000
                        result.append('\x00')
                        result.append(chr(self._runCount & 0xff))
                        result.append(chr((self._runCount >> 8) & 0xff))
Das mehr als 0xFFFF gleiche Bytes aufeinanderfolgen kann in dieser Methode eigentlich nie passieren. Das wird an anderer Stelle sichergestellt. Falls es aber doch passiert, dann ist dieses ``assert`` da und schlägt Alarm.

Aus einem Text-Parser der auf bestimmte Kommandozeilen reagiert:

Code: Alles auswählen

    def _get_commandline_count(self):
        """Calculates number of processed command lines.
        
        :returns: number of processed command lines.
        :rtype: int
        """
        result = self.line_number - self.textline_count
        assert result >= 0
        return result
Der Parser zählt die Textzeilen, also solche die kein Kommando enthalten, und die Gesamtzeilen. Diese Differenz darf nie negativ sein.
lunar

Mittwoch 27. Dezember 2006, 23:30

Zusammenfassung von mir:
  • Ausnahmen sind Fehler, die zur Laufzeit zwar nicht erwünscht, aber doch möglich sind, wie z.B. das Fehlen einer Datei; eben Ausnahmen vom normalen Programmablauf.
  • Mit assert Anweisungen dagegen sollten zur Laufzeit des Programmes niemals fehlschlagen. Tun sie es doch, ist das eben nicht nur eine Ausnahmesituation, sondern ein kapitaler Fehler in der Programmlogik.
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Mittwoch 27. Dezember 2006, 23:54

Ich danke euch für die Erklärung. Ich werde das dann wohl wie bisher nicht nutzen, sondern nur Unittests weiter benutzen, weil es wohl eigentlich ausreichend ist.

lg
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Donnerstag 28. Dezember 2006, 12:58

sape hat geschrieben:Ich werde das dann wohl wie bisher nicht nutzen
Assert nutzen auch nur wenige Programmierer und auch dann eher selten. In den Quellcodes die mir so untergekommen sinnd, waren nie viele Asserts drinnen. Ich selbst nutze keine - Fehler in der Programmlogik sind bei mir ja ausgeschlossen 8)
My god, it's full of CARs! | Leonidasvoice vs Modvoice
BlackJack

Donnerstag 28. Dezember 2006, 13:54

Das denke ich mir auch oft. Häufig ist ein ``assert`` im Quelltext die Folge eines Fehlers, den ich an der Stelle mal entdeckt habe. :-)
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Freitag 29. Dezember 2006, 00:26

Nehme alles zurück. Nun benutze ich seit heute auch assert in dem Parser, der den Python Quellencode in einem AST anbildet. Da ist es nützlich für mich stellen zu "markieren" die einen bestimmten Zustand niemals annehmen dürfe (vorher hatte ich dafür eine überprüfung gemacht und dann ne Exception geworfen). Da der Parser noch nicht fertig ist kommt das bei bestimmten Konstellationen zustande und ich habe dann ein gutes Indiz wo ich noch was vergessen habe (Wie z.B. die Docstrings die sich über mehrere Zeilen erstrecken.).

Dank eurer Tipps von gestern weiß ich nun, dass an solchen stellen wo von einem Programmfehler ausgegangen werden muss, keine Exceptions als "Marker" hingehören :) Danke nochmals für eure Tipps.

Aber noch eine Frage habe ich:
Nehmt ihr die assert Bedingungen wenn eurer Code Perfekt funktioniert wider weck oder lässt ihr die einfach drin? Ich hab mir überlegt wenn mein Parser zu 99% Fehlerfrei funktioniert, das ich die asserts auskommentieren, zwecks Performance. Oder sollte ich mir wegen der Performance keine großen Gedanken machen?

lg
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Freitag 29. Dezember 2006, 00:42

sape hat geschrieben:Ich hab mir überlegt wenn mein Parser zu 99% Fehlerfrei funktioniert, das ich die asserts auskommentieren, zwecks Performance. Oder sollte ich mir wegen der Performance keine großen Gedanken machen?
Hast du deswegen Performanceprobleme? Nein? Dann lass sie drin. Ich habe Zweifel, ob der Performanceunterschied mit und ohne assert mehr als ein halbes Prozent ausmacht.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Freitag 29. Dezember 2006, 00:48

OK, danke Leo, dann bleiben die drinnen :)

lg
Benutzeravatar
jens
Moderator
Beiträge: 8481
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Freitag 29. Dezember 2006, 10:09

asserts werden ignoriert, wenn man den Optimize Modus benutzt ;) Siehe http://www.python-forum.de/topic-7472.html

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Freitag 29. Dezember 2006, 14:00

jens hat geschrieben:asserts werden ignoriert, wenn man den Optimize Modus benutzt ;) Siehe http://www.python-forum.de/topic-7472.html
Oder siehe den Thread hier, denn gerold hat dies schon ein paar Posts früher geschrieben :roll:
My god, it's full of CARs! | Leonidasvoice vs Modvoice
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Freitag 29. Dezember 2006, 15:34

Leonidas hat geschrieben:
jens hat geschrieben:asserts werden ignoriert, wenn man den Optimize Modus benutzt ;) Siehe http://www.python-forum.de/topic-7472.html
Oder siehe den Thread hier, denn gerold hat dies schon ein paar Posts früher geschrieben :roll:
Erstens, ich habe den post von Gerlod gelesen und zweitens, ich lese grundsätzlich alle posts (sogar mehrmals! Und das gilt auch für Threads bis ca. 20 Seiten.)! :evil:


Gerold hat ja auch geschrieben
Wenn man irgendwann alle ``assert``-Anweisungen los werden will, dann ist das mit einem Editor, der suchen kann, in wenigen Minuten erledigt.
.

Daher stellte ich die Frage...
Nehmt ihr die assert Bedingungen wenn eurer Code Perfekt funktioniert wider weck oder lässt ihr die einfach drin? Ich hab mir überlegt wenn mein Parser zu 99% Fehlerfrei funktioniert, das ich die asserts auskommentieren, zwecks Performance. Oder sollte ich mir wegen der Performance keine großen Gedanken machen?
, weil ich wissen wollte ob ihr asserts bei 100%ig funktionierenden Code entfernt weil...
a.) Sich die Performance erhöht? (ist ja nun geklärt -> ca. 0.5%)
b.) Um Toten-Code loszuwerden (ok, habe ich nicht erwähnt wo ich meinen post gerade lese ^^)
c.) Wegen anderen gründen?

So und nun Frieden meine Herren :D ;)

Um ein wenig Spaß reinzubringen: Nun sehe ich das ich assert zu oft nutze (komischerweise nur im Parser). Hab da jetzt ne Ladung die ich nach funktionierenden Code doch entsorgen werde ^^

:)

lg
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Freitag 29. Dezember 2006, 15:47

sape hat geschrieben:a.) Sich die Performance erhöht? (ist ja nun geklärt -> ca. 0.5%)
Nein, natürlich nicht 0,5%! 0,5% war ein Schätzwert von mir, womit ich andeuten wollte, dass es sehr wenig sein wird. Wie viel Prozent es tatsächlich sind, müsstest du mit dem Profiler nachmessen. Aber große Unterschiede sind eher nicht zu erwarten. Außer du hast in jeder zweiten Zeile ein Assert und/oder der Assert-Code wird sehr oft ausgeführt.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
BlackJack

Freitag 29. Dezember 2006, 16:00

Es kommt letztendlich auch auf den Code an, der im ``assert`` ausgeführt wird. Da können schliesslich beliebige Ausdrücke stehen, auch solche die wirklich viel Code ausführen, eine Verbindung zu einer Datenbank aufbauen oder ähnliche Zeitfresser.

Zumindest für ``assert``s die Nachbedingungen oder Klasseninvarianten prüfen, kann man Unit-Tests schreiben. Dann geht der Test nicht ganz verloren, falls man das ``assert`` entfernt, sondern wird nur für ausgewählte Testfälle ausgeführt.
Antworten