Check First vs Ausnahmebehandlung?

88

Ich arbeite an dem Buch "Head First Python" (es ist meine Sprache, die ich in diesem Jahr lernen muss) und ich komme zu einem Abschnitt, in dem über zwei Codetechniken gestritten wird:
Die Behandlung von "Checking First vs Exception".

Hier ist ein Beispiel des Python-Codes:

# Checking First
for eachLine in open("../../data/sketch.txt"):
    if eachLine.find(":") != -1:
        (role, lineSpoken) = eachLine.split(":",1)
        print("role=%(role)s lineSpoken=%(lineSpoken)s" % locals())

# Exception handling        
for eachLine in open("../../data/sketch.txt"):
    try:
        (role, lineSpoken) = eachLine.split(":",1)
        print("role=%(role)s lineSpoken=%(lineSpoken)s" % locals())
    except:
        pass

Das erste Beispiel befasst sich direkt mit einem Problem in der .splitFunktion. Der zweite lässt nur den Ausnahmehandler damit umgehen (und ignoriert das Problem).

Sie argumentieren im Buch, die Ausnahmebehandlung zu verwenden, anstatt zuerst zu prüfen. Das Argument ist, dass der Ausnahmecode alle Fehler auffängt, wobei das Überprüfen zuerst nur die Dinge auffängt, über die Sie nachdenken (und Sie die Eckfälle verpassen). Mir wurde beigebracht, zuerst nachzuschauen, also war es mein erster Instinkt, das zu tun, aber ihre Idee ist interessant. Ich hatte nie daran gedacht, die Ausnahmebehandlung für die Bearbeitung von Fällen zu verwenden.

Welches der beiden Verfahren wird allgemein als die bessere Praxis angesehen?

jmq
quelle
12
Dieser Abschnitt im Buch ist nicht klug. Wenn Sie sich in einer Schleife befinden und immer wieder Ausnahmen auslösen, ist dies sehr kostspielig. Ich habe versucht, einige gute Punkte zu skizzieren, wann ich das tun soll.
Jason Sebring
9
Fallen Sie einfach nicht in die "file exists check" -Falle. Datei existiert! = Hat
Billy ONeal
11
Ausnahmen werden in Python anders gedacht als in anderen Sprachen. Beispielsweise können Sie eine Auflistung durchlaufen, indem Sie .next () aufrufen, bis eine Ausnahme ausgelöst wird.
WuHoUnited
4
@ emeraldcode.com Das stimmt nicht ganz mit Python. Ich kenne die Besonderheiten nicht, aber die Sprache wurde um dieses Paradigma herum entwickelt, so dass das Werfen von Ausnahmen nicht annähernd so teuer ist wie in anderen Sprachen.
Izkata
Das heißt, für dieses Beispiel würde ich eine Guard-Anweisung verwenden:, if -1 == eachLine.find(":"): continuedann würde der Rest der Schleife auch nicht eingerückt werden.
Izkata

Antworten:

68

In .NET ist es gängige Praxis, die übermäßige Verwendung von Ausnahmen zu vermeiden. Ein Argument ist die Leistung: In .NET ist das Auslösen einer Ausnahme rechenintensiv.

Ein weiterer Grund, um eine Überbeanspruchung zu vermeiden, besteht darin, dass es sehr schwierig sein kann, Code zu lesen, der zu stark von ihnen abhängt. Joel Spolskys Blog-Eintrag liefert eine gute Beschreibung des Problems.

Im Zentrum des Arguments steht das folgende Zitat:

Der Grund dafür ist, dass ich Ausnahmen nicht besser halte als "goto's", die seit den 1960er Jahren als schädlich angesehen werden, da sie einen abrupten Sprung von einem Codepunkt zum anderen bewirken. Tatsächlich sind sie bedeutend schlechter als die folgenden:

1. Sie sind im Quellcode unsichtbar . Wenn Sie sich einen Codeblock ansehen, der Funktionen enthält, die möglicherweise Ausnahmen auslösen, können Sie nicht feststellen, welche Ausnahmen von wo ausgelöst werden. Dies bedeutet, dass selbst eine sorgfältige Code-Überprüfung keine potenziellen Fehler aufdeckt.

2. Sie erzeugen zu viele mögliche Austrittspunkte für eine Funktion. Um korrekten Code zu schreiben, müssen Sie wirklich über jeden möglichen Codepfad durch Ihre Funktion nachdenken. Jedes Mal, wenn Sie eine Funktion aufrufen, die eine Ausnahme auslösen kann und diese nicht sofort abfängt, können Überraschungsfehler auftreten, die durch Funktionen verursacht werden, die abrupt beendet wurden und die Daten in einem inkonsistenten Zustand belassen, oder durch andere Codepfade, die Sie nicht gefunden haben nachdenken über.

Persönlich mache ich Ausnahmen, wenn mein Code nicht das kann, wozu er vertraglich verpflichtet ist. Ich benutze normalerweise try / catch, wenn ich mit etwas außerhalb meiner Prozessgrenze zu tun habe, zum Beispiel mit einem SOAP-Aufruf, einem Datenbankaufruf, einer Datei-E / A oder einem Systemaufruf. Ansonsten versuche ich defensiv zu codieren. Es ist keine feste Regel, aber es ist eine allgemeine Praxis.

Scott Hanselman schreibt hier auch über Ausnahmen in .NET . In diesem Artikel beschreibt er einige Faustregeln in Bezug auf Ausnahmen. Mein Lieblings?

Sie sollten keine Ausnahmen für Dinge werfen, die die ganze Zeit passieren. Dann wären sie "Ordinaries".

Kyle Hodgson
quelle
5
Hier ist ein weiterer Punkt: Wenn die Ausnahmenprotokollierung anwendungsweit aktiviert ist, ist es besser, die Ausnahme nur für Ausnahmebedingungen zu verwenden, nicht für gewöhnliche Bedingungen. Andernfalls wird das Protokoll unübersichtlich und die eigentlichen Fehlerursachen werden ausgeblendet.
rwong
2
Gute Antwort. Beachten Sie jedoch, dass Ausnahmen auf den meisten Plattformen einen hohen Leistungseffekt haben. Wie Sie jedoch bei meinen Kommentaren zu anderen Antworten bemerkt haben, spielt die Leistung keine Rolle, wenn es darum geht, eine pauschale Regel für die Kodifizierung von etwas festzulegen.
Mattnz
1
Das Zitat von Scott Hanselman beschreibt die .Net-Haltung gegenüber Ausnahmen besser als "Überbeanspruchung". Die Leistung wird häufig erwähnt, aber das eigentliche Argument ist das Gegenteil davon, warum Sie Ausnahmen verwenden SOLLTEN - es erschwert das Verständnis und die Behandlung des Codes, wenn eine gewöhnliche Bedingung zu einer Ausnahme führt. Was Joel betrifft, ist Punkt 1 tatsächlich positiv (unsichtbar bedeutet, dass Code zeigt, was er tut, nicht was er nicht tut) und Punkt 2 irrelevant (Sie befinden sich bereits in einem inkonsistenten Zustand, oder es sollte keine Ausnahme geben). . Trotzdem +1 für "kann nicht tun, wozu es aufgefordert wurde".
Jmoreno
5
Obwohl diese Antwort für .Net in Ordnung ist, ist sie nicht sehr pythonisch. Da es sich also um eine Python-Frage handelt, verstehe ich nicht, warum Ivcs Antwort nicht mehr bewertet wurde .
Mark Booth
2
@ IanGoldby: Nein. Die Ausnahmebehandlung wird eigentlich besser als Ausnahmewiederherstellung bezeichnet. Wenn Sie eine Ausnahme nicht beheben können, sollten Sie wahrscheinlich keinen Ausnahmebehandlungscode haben. Wenn die Methode A die Methode B aufruft, die C aufruft, und C auslöst, sollte sich mit hoher Wahrscheinlichkeit WEDER A ODER B erholen, nicht beides. Die Entscheidung "Wenn ich X nicht kann, mache ich Y" sollte vermieden werden, wenn Y erfordert, dass jemand anderes die Aufgabe beendet. Wenn Sie die Aufgabe nicht abschließen können, müssen Sie nur noch bereinigen und protokollieren. Die Bereinigung in .net sollte automatisch erfolgen, die Protokollierung sollte zentralisiert werden.
Jmoreno
78

Insbesondere in Python wird es normalerweise als besser angesehen, die Ausnahme abzufangen. Im Vergleich zu Look Before You Leap (LBYL) wird es als einfacher empfunden, um Vergebung zu bitten als um Erlaubnis (EAFP). Es gibt Fälle, in denen LBYL in einigen Fällen subtile Fehler verursacht .

Seien Sie jedoch vorsichtig mit nackten except:Anweisungen sowie mit Overbroad-Ausnahmen, da sie beide auch Fehler maskieren können - so etwas wäre besser:

for eachLine in open("../../data/sketch.txt"):
    try:
        role, lineSpoken = eachLine.split(":",1)
    except ValueError:
        pass
    else:
        print("role=%(role)s lineSpoken=%(lineSpoken)s" % locals())
lvc
quelle
8
Als .NET-Programmierer schaudere ich dabei. Aber andererseits macht ihr Leute alles seltsam. :)
Phil
Dies ist ausgesprochen frustrierend (Wortspiel nicht vorgesehen), wenn APIs nicht konsistent sind, welche Ausnahmen unter welchen Umständen ausgelöst werden, oder wenn mehrere verschiedene Arten von Fehlern unter demselben Ausnahmetyp ausgelöst werden.
Jack
Daher verwenden Sie denselben Mechanismus für unerwartete Fehler und erwartete Rückgabewerte. Das ist ungefähr so ​​gut wie die Verwendung von 0 als Zahl, eines falschen Bools UND eines ungültigen Zeigers, der Ihren Prozess mit einem Exit-Code von 128 + SIGSEGV beendet. Wie praktisch, Sie brauchen jetzt keine anderen Dinge. Wie der Spork! Oder Schuhe mit Zehen ...
Yeoman
2
@yeoman, wenn eine Ausnahme ausgelöst werden soll , ist eine andere Frage. In dieser Frage geht es darum, try/ zu verwenden, exceptanstatt eine Bedingung einzurichten, für die "Folgendes wahrscheinlich eine Ausnahme auslöst ", und die Python-Praxis ist definitiv die erstere zu bevorzugen. Es tut nicht weh, dass dieser Ansatz hier (wahrscheinlich) effizienter ist, da Sie in dem Fall, in dem die Aufteilung erfolgreich ist, die Saite nur einmal laufen. Was die Frage splitbetrifft , ob hier eine Ausnahme ausgelöst werden soll, würde ich sagen, dass dies definitiv der Fall sein sollte. Eine gängige Regel ist, dass Sie eine Ausnahme auslösen sollten, wenn Sie nicht das tun können, was Ihr Name sagt, und Sie nicht an einem fehlenden Trennzeichen trennen können.
lvc
Ich finde es nicht schlecht oder langsam oder schrecklich, zumal nur eine bestimmte Ausnahme abgefangen wird. Ans Ich mag eigentlich Python. Es ist einfach lustig, wie es manchmal überhaupt keinen Geschmack zeigt, wie die Verwendung der Nummer 0, des Spork und Randall Munroes Lieblingsschuhe mit Zehen Egal, wie es geht, ich werde es versuchen :) Die Bedingungen im Voraus zu überprüfen, ist natürlich keine gute Idee, da Parallelen, Koroutinen oder eine davon später hinzugefügt werden ...
yeoman
27

Ein pragmatischer Ansatz

Sie sollten aber bis zu einem gewissen Punkt defensiv sein. Sie sollten die Ausnahmebehandlung aber auf einen Punkt schreiben. Ich werde das Webprogrammieren als Beispiel verwenden, weil ich hier wohne.

  1. Nehmen Sie an, dass alle Benutzereingaben fehlerhaft sind, und schreiben Sie defensiv nur bis zum Punkt der Datentypüberprüfung, der Musterüberprüfung und der böswilligen Injektion. Defensive Programmierung sollte Dinge sein, die möglicherweise sehr oft vorkommen können und die Sie nicht kontrollieren können.
  2. Schreiben Sie eine Ausnahmebehandlung für Netzwerkdienste, die manchmal fehlschlagen, und behandeln Sie sie ordnungsgemäß für Benutzerfeedback. Die Ausnahmeprogrammierung sollte für vernetzte Dinge verwendet werden, die von Zeit zu Zeit fehlschlagen, aber normalerweise solide sind, UND Sie müssen Ihr Programm am Laufen halten.
  3. Machen Sie sich nicht die Mühe, in Ihrer Anwendung defensiv zu schreiben, nachdem die Eingabedaten überprüft wurden. Es ist eine Verschwendung von Zeit und bläht Ihre App. Lassen Sie es explodieren, weil es entweder etwas sehr Seltenes ist , das es nicht wert ist, behandelt zu werden, oder weil Sie Schritt 1 und 2 genauer betrachten müssen.
  4. Schreiben Sie niemals eine Ausnahmebehandlung in Ihren Kerncode, die nicht von einem vernetzten Gerät abhängig ist. Dies ist schlecht programmiert und teuer für die Leistung. Zum Beispiel bedeutet das Schreiben eines Try-Catchs im Falle eines außerhalb der Grenzen liegenden Arrays in einer Schleife, dass Sie die Schleife nicht an erster Stelle richtig programmiert haben.
  5. Lassen Sie alles durch eine zentrale Fehlerprotokollierung erledigen, die Ausnahmen an einer Stelle abfängt, nachdem Sie die oben beschriebenen Verfahren ausgeführt haben. Sie können nicht jeden Kantenfall abfangen, da dieser möglicherweise unendlich ist. Sie müssen nur Code schreiben, der die erwartete Operation handhabt. Deshalb setzen Sie als letzten Ausweg die zentrale Fehlerbehandlung ein.
  6. TDD ist nett, denn es ist in gewisser Weise ein Versuchsfang für Sie, ohne sich aufzublähen, was bedeutet, dass Sie eine gewisse Sicherheit für den normalen Betrieb haben.
  7. Bonuspunkte erhalten Sie, wenn Sie ein Code-Coverage-Tool verwenden. Istanbul ist beispielsweise eine gute Lösung für Knoten, da dies zeigt, wo Sie nicht testen.
  8. Die Einschränkung bei alledem sind entwicklerfreundliche Ausnahmen . Zum Beispiel würde eine Sprache werfen, wenn Sie die Syntax falsch verwenden und erklären, warum. So sollten Ihre Utility- Bibliotheken, von denen der Großteil Ihres Codes abhängt.

Dies ist aus Erfahrung in großen Teamszenarien.

Eine Analogie

Stellen Sie sich vor, Sie hätten die ganze Zeit einen Raumanzug in der ISS getragen. Es würde schwer sein, auf die Toilette zu gehen oder überhaupt zu essen. Es wäre super sperrig, sich innerhalb des Weltraummoduls zu bewegen. Es wäre scheiße. So ähnlich ist es, eine Reihe von Versuchsfängen in Ihren Code zu schreiben. Sie müssen irgendwann wissen, wo Sie sagen: Hey, ich habe die ISS gesichert, und meine Astronauten sind in Ordnung. Es ist also einfach nicht praktisch, für jedes Szenario, das möglicherweise passieren könnte, einen Raumanzug zu tragen.

Jason Sebring
quelle
4
Das Problem bei Punkt 3 ist, dass davon ausgegangen wird, dass das Programm und die daran arbeitenden Programmierer perfekt sind. Sie sind es nicht, deshalb ist es das beste Programm, wenn Sie dies im Auge behalten. Angemessene Mengen an der Schlüsselstelle können die Software weitaus zuverlässiger machen als die Mentalität "Wenn die Eingaben überprüft werden, ist alles perfekt".
Mattnz
Dafür ist Testen da.
Jason Sebring
3
Testen ist nicht alles. Ich habe noch keine Testsuite mit 100% Code und "Umgebungs" -Abdeckung gesehen.
Marjan Venema
1
@emeraldcode: Möchten Sie einen Job bei mir? Ich hätte gerne jemanden im Team, der mit Ausnahme der Tests immer jede Permutation für jeden Randfall testet, den die Software jemals ausführen wird. Es muss schön sein, mit absoluter Gewissheit zu wissen, dass Ihr Code perfekt getestet wurde.
Mattnz
1
Zustimmen. Es gibt Szenarien, in denen sowohl defensive Programmierung als auch Ausnahmebehandlung gut und schlecht funktionieren, und wir als Programmierer sollten lernen, sie zu erkennen und die Technik zu wählen, die am besten passt. Ich mag Punkt 3, weil ich glaube, dass wir auf einer bestimmten Codeebene davon ausgehen müssen, dass einige Kontextbedingungen erfüllt sein sollten. Diese Bedingungen werden durch defensives Codieren in der äußeren Codeschicht erfüllt, und ich denke, die Ausnahmebehandlung passt, wenn diese Annahmen in der inneren Schicht verletzt werden.
Yaobin
15

Das Hauptargument des Buches ist, dass die Ausnahmeversion des Codes besser ist, da sie alles auffängt, was Sie möglicherweise übersehen hätten, wenn Sie versucht hätten, Ihre eigene Fehlerprüfung zu schreiben.

Ich denke, diese Aussage trifft nur unter ganz bestimmten Umständen zu - wobei es Ihnen egal ist, ob die Ausgabe korrekt ist.

Es besteht kein Zweifel, dass das Auslösen von Ausnahmen eine solide und sichere Praxis ist. Sie sollten dies tun, wenn Sie das Gefühl haben, dass sich im aktuellen Status des Programms etwas befindet, mit dem Sie (als Entwickler) nicht umgehen können oder wollen.

In Ihrem Beispiel geht es jedoch darum , Ausnahmen einzufangen . Wenn Sie eine Ausnahme feststellen , schützen Sie sich nicht vor Szenarien, die Sie möglicherweise übersehen haben. Sie tun genau das Gegenteil: Sie gehen davon aus, dass Sie kein Szenario übersehen haben, das diese Art von Ausnahme verursacht haben könnte, und sind daher zuversichtlich, dass es in Ordnung ist, sie abzufangen (und somit zu verhindern, dass das Programm beendet wird, wie es jede unaufgefangene Ausnahme tun würde).

Wenn Sie den ValueErrorAusnahmeansatz verwenden und eine Ausnahme sehen, überspringen Sie eine Zeile. Bei Verwendung des herkömmlichen Ansatzes ohne Ausnahmen wird die Anzahl der zurückgegebenen Werte von gezählt split, und bei weniger als 2 wird eine Zeile übersprungen. Sollten Sie sich mit dem Ausnahmeansatz sicherer fühlen, da Sie möglicherweise einige andere "Fehler" -Situationen bei Ihrer herkömmlichen Fehlerprüfung vergessen haben und except ValueErrordiese für Sie abfangen würden?

Dies hängt von der Art Ihres Programms ab.

Wenn Sie beispielsweise einen Webbrowser oder einen Videoplayer schreiben, sollte ein Problem mit Eingaben nicht dazu führen, dass er mit einer nicht erfassten Ausnahme abstürzt. Es ist weitaus besser, etwas aus der Ferne Vernünftiges (auch wenn es streng genommen falsch ist) auszugeben, als zu beenden.

Wenn Sie eine Anwendung schreiben, bei der es auf Korrektheit ankommt (z. B. Geschäfts- oder Entwicklungssoftware), ist dies ein schrecklicher Ansatz. Wenn Sie ein ausgelöstes Szenario vergessen ValueErrorhaben, können Sie dieses unbekannte Szenario im Stillen ignorieren und einfach die Zeile überspringen. So entstehen sehr subtile und kostspielige Fehler in der Software.

Sie könnten denken, dass die einzige Möglichkeit, die Sie ValueErrorin diesem Code sehen können, darin besteht, splitnur einen Wert (anstelle von zwei) zurückzugeben. Aber was ist, wenn Ihre printAnweisung später einen Ausdruck verwendet, der ValueErrorunter bestimmten Bedingungen ausgelöst wird? Dies führt dazu, dass Sie einige Zeilen überspringen, nicht weil sie fehlen :, sondern weil sie printnicht funktionieren. Dies ist ein Beispiel für einen subtilen Fehler, auf den ich mich früher bezogen habe - Sie würden nichts bemerken, sondern nur einige Zeilen verlieren.

Ich empfehle, keine Ausnahmen im Code abzufangen (aber nicht zu erhöhen!), Bei denen das Erzeugen einer falschen Ausgabe schlechter ist als das Beenden. Das einzige Mal, dass ich eine Ausnahme in einem solchen Code abfange, ist, wenn ich einen wirklich trivialen Ausdruck habe, sodass ich leicht überlegen kann, was die einzelnen möglichen Ausnahmetypen verursachen kann.

Die Auswirkungen der Verwendung von Ausnahmen auf die Leistung sind (in Python) trivial, es sei denn, Ausnahmen treten häufig auf.

Wenn Sie Ausnahmen verwenden, um routinemäßig auftretende Bedingungen zu behandeln, können Sie in einigen Fällen enorme Leistungskosten zahlen. Angenommen, Sie führen einen Befehl aus der Ferne aus. Sie können überprüfen, ob Ihr Befehlstext mindestens die Mindestvalidierung (z. B. Syntax) besteht. Oder Sie können warten, bis eine Ausnahme ausgelöst wird (was erst geschieht, nachdem der Remoteserver Ihren Befehl analysiert und ein Problem damit gefunden hat). Ersteres ist offensichtlich um Größenordnungen schneller. Ein weiteres einfaches Beispiel: Sie können überprüfen, ob eine Zahl null bis zehn Mal schneller ist als der Versuch, die Division auszuführen, und dann die ZeroDivisionError-Ausnahme abfangen.

Diese Überlegungen spielen nur eine Rolle, wenn Sie häufig fehlerhafte Befehlszeichenfolgen an Remoteserver senden oder Argumente mit dem Wert Null empfangen, die Sie für die Aufteilung verwenden.

Hinweis: Ich gehe davon aus, dass Sie except ValueErroranstelle des Gerechten verwenden würden except. Wie andere betonten, und wie das Buch selbst auf einigen Seiten sagt, sollten Sie niemals nackte verwenden except.

Ein weiterer Hinweis: Der richtige Ansatz ohne Ausnahmen besteht darin, die Anzahl der von zurückgegebenen Werte zu zählen split, anstatt zu suchen :. Letzteres ist viel zu langsam, da es die von Ihnen geleistete Arbeit wiederholt splitund die Ausführungszeit möglicherweise fast verdoppelt.

max
quelle
6

Wenn Sie wissen, dass eine Anweisung zu einem ungültigen Ergebnis führen kann, testen Sie dies in der Regel und gehen Sie damit um. Verwenden Sie Ausnahmen für Dinge, die Sie nicht erwarten. Zeug, das "außergewöhnlich" ist. Es macht den Code im vertraglichen Sinne klarer ("sollte nicht null sein" als Beispiel).

Ian
quelle
2

Verwenden Sie, was immer gut funktioniert ..

  • Ihre gewählte Programmiersprache in Bezug auf Lesbarkeit und Effizienz des Codes
  • Ihr Team und die vereinbarten Code-Konventionen

Sowohl die Ausnahmebehandlung als auch die defensive Programmierung sind verschiedene Arten, die gleiche Absicht auszudrücken.

Sri
quelle
0

TBH, es ist egal, ob Sie den try/exceptMechaniker oder eine ifAnweisungsprüfung verwenden. Sie sehen sowohl EAFP als auch LBYL in den meisten Python-Baselines, wobei EAFP etwas häufiger vorkommt. Manchmal EAFP ist viel besser lesbar / idiomatische, aber in diesem speziellen Fall denke ich , dass es so oder so in Ordnung.

Jedoch...

Ich würde mit Ihrer aktuellen Referenz vorsichtig sein. Ein paar krasse Probleme mit ihrem Code:

  1. Der Dateideskriptor ist durchgesickert. In modernen Versionen von CPython (einem bestimmten Python-Interpreter) wird es tatsächlich geschlossen, da es sich um ein anonymes Objekt handelt, das sich nur während der Schleife im Gültigkeitsbereich befindet (gc wird es nach der Schleife nuklearisieren). Andere Dolmetscher haben diese Garantie jedoch nicht . Sie können den Deskriptor direkt auslaufen lassen. Sie möchten fast immer das withIdiom verwenden, wenn Sie Dateien in Python lesen: Es gibt nur sehr wenige Ausnahmen. Das ist keiner von ihnen.
  2. Die Behandlung von Pokemon-Ausnahmen wird verpönt, da sie Fehler maskiert (dh eine bloße exceptAnweisung, die keine bestimmte Ausnahme abfängt).
  3. Nit: Sie brauchen keine Parens zum Auspacken von Tupeln. Kann einfach machenrole, lineSpoken = eachLine.split(":",1)

Ivc hat eine gute Antwort zu diesem und dem EAFP, gibt aber auch den Deskriptor preis.

Die LBYL-Version ist nicht unbedingt so performant wie die EAFP-Version, weshalb das Auslösen von Ausnahmen "in Bezug auf die Leistung teuer" grundsätzlich falsch ist. Es hängt wirklich von der Art der Zeichenfolgen ab, die Sie verarbeiten:

In [33]: def lbyl(lines):
    ...:     for line in lines:
    ...:         if line.find(":") != -1:
    ...:             # Nuke the parens, do tuple unpacking like an idiomatic Python dev.
    ...:             role, lineSpoken = line.split(":",1)
    ...:             # no print, since output is obnoxiously long with %timeit
    ...:

In [34]: def eafp(lines):
    ...:     for line in lines:
    ...:         try:
    ...:             # Nuke the parens, do tuple unpacking like an idiomatic Python dev.
    ...:             role, lineSpoken = eachLine.split(":",1)
    ...:             # no print, since output is obnoxiously long with %timeit
    ...:         except:
    ...:             pass
    ...:

In [35]: lines = ["abc:def", "onetwothree", "xyz:hij"]

In [36]: %timeit lbyl(lines)
100000 loops, best of 3: 1.96 µs per loop

In [37]: %timeit eafp(lines)
100000 loops, best of 3: 4.02 µs per loop

In [38]: lines = ["a"*100000 + ":" + "b", "onetwothree", "abconetwothree"*100]

In [39]: %timeit lbyl(lines)
10000 loops, best of 3: 119 µs per loop

In [40]: %timeit eafp(lines)
100000 loops, best of 3: 4.2 µs per loop
Matt Messersmith
quelle
-4

Grundsätzlich sollte die Ausnahmebehandlung für OOP-Sprachen besser geeignet sein.

Der zweite Punkt ist die Leistung, da Sie nicht eachLine.findfür jede Zeile ausführen müssen .

Elalfer
quelle
7
-1: Die Leistung ist ein extrem schlechter Grund für Pauschalregeln.
Mattnz
3
Nein, Ausnahmen haben nichts mit OOP zu tun.
Pubby
-6

Ich denke, defensive Programmierung schadet der Leistung. Sie sollten auch nur die Ausnahmen abfangen, die Sie behandeln möchten, und die Laufzeitumgebung mit der Ausnahme befassen, die Sie nicht behandeln können.

Manoj
quelle
7
Trotzdem anotehr -1 für die Sorge um Leistung über Lesbarkeit, Wartbarkeit bla bla bla. Leistung ist kein Grund.
Mattnz
Darf ich wissen, warum Sie herumlaufen und -1s verteilen, ohne es zu erklären? Defensive Programmierung bedeutet mehr Codezeilen, dh schlechtere Leistung. Möchte jemand etwas erklären, bevor er die Partitur abschießt?
Manoj
3
@Manoj: Sofern Sie nicht mit einem Profiler gemessen und festgestellt haben, dass ein Codeblock unannehmbar langsam ist, ist der Code für Lesbarkeit und Wartbarkeit weit vor der Leistung.
Daenyth
Was @Manoj mit dem Zusatz sagte, dass weniger Code im Allgemeinen weniger Arbeit beim Debuggen und Warten bedeutet. Die Entwicklerzeit für weniger als den perfekten Code ist extrem hoch. Ich gehe davon aus (wie ich), dass Sie keinen perfekten Code schreiben. Verzeihen Sie mir, wenn ich falsch liege.
Mattnz
2
Vielen Dank für den Link - Interessant zu lesen, dass ich bis zu einem gewissen Punkt damit einverstanden sein muss ... "Das System druckte den Stack-Trace, sodass wir genau wissen, warum diese 300 Menschen unnötig starben. .... "wird im Zeugenstand nicht wirklich gut ankommen. Ich nehme an, es ist eines dieser Dinge, bei denen jede Situation eine andere angemessene Reaktion hat.
Mattnz