Seite 1 von 1
PHP-Umsteiger braucht etwas Starthilfe ;)
Verfasst: Sonntag 24. Juni 2012, 14:11
von Malachite
Joa, moin erstmal,
wie ihr unschwer an der Überschrift erkennen könnt, komme ich aus dem PHP-Lager, möchte jetzt mit Python anfangen und brauche dabei etwas Starthilfe.
Mir geht es vor allem um die Python-Pendants zu einigen PHP-Befehlen und -Operatoren.
Ich habe unter Anderem schon herausgefunden, dass das Äquivalent zu
in Python
ist… oder so ähnlich. Für den sehr wahrscheinlichen Fall, dass ich falsch liege, korrigiert mich bitte

.
Außerdem suche ich noch die Pendants zu folgenden Funktionen:
- is_subclass_of() - ermittelt, ob eine Klasse (oder deren Instanz) eine Unterklasse einer anderen ist
- class_parents() – ermittelt die Elternklassen einer Klasse
- is_numeric() – gibt true zurück, wenn der Parameter eine Zahl ist
- set_exception_handler() - Nachdem diese Funktion mit einer anderen Funktion als Parameter ausgeführt wird, fängt Letztere alle ungefangenen Ausnahmen ab. Praktisch, um ein paar try/catch- (bzw. try/except-) Blöcke zu sparen, vor Allem, wenn sowieso für jede Ausnahme die gleiche Funktion ausgeführt wird
Ich hoffe, ihr könnt mir helfen.
Re: PHP-Umsteiger braucht etwas Starthilfe ;)
Verfasst: Sonntag 24. Juni 2012, 14:55
von BlackJack
@Malachite: Die Dokumentation von `isinstance()` spricht nicht von einer Liste als zweites Argument. Wenn man es mal ausprobiert:
Code: Alles auswählen
In [393]: isinstance(42, [int])
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
/home/bj/<ipython console> in <module>()
TypeError: isinstance() arg 2 must be a class, type, or tuple of classes and types
Gib einfach den Typ direkt an:
Alternativ kann man auch ein Tupel mit Typen angeben, dann ist der Ausdruck wahr wenn mindestens einer der Typen zutrifft.
`is_subclass_of()` wird wahrscheinlich `issubclass()` sein. `class_parents()` wahrscheinlich das `__bases__`-Attribut, wobei ich jetzt nicht weiss ob das ein Implementierungsdetail ist. `inspect.getclasstree()` sollte implementierungsunabhängig funktionieren.
`is_numeric()` gibt es nicht — braucht man in einer Sprache wo es eine klare Trennung zwischen Zahlen und Zeichenketten gibt, aber IMHO auch nicht wirklich.
Genau so sind die anderen Funktionen eher „Exoten”. Wenn man oft auf konkrete Typen oder Unterklassen testen muss, hat man objektorientierte Programmierung nicht verstanden und unterläuft zudem das „duck typing” von Python.
Der Sinn von `set_exception_handler()` erschliesst sich mir jetzt nicht wirklich. Wenn Du alle Ausnahmen abfangen willst — was man in der Regel gar nicht wollen sollte — kann man ein nacktes ``except:`` verwenden. Aber wie gesagt, davon sollte man Abstand nehmen, denn selten bis nie kann man an einer Stelle wirklich *alle* Ausnahmen *sinnvoll* behandeln, denn man weiss ja gar nicht welche das alle sein können. Und bei einigen wie zum Beispiel einem `MemoryError` weiss ich auch nicht wie man da sinnvoll weitermachen könnte wenn man ihn einfach ignoriert‽ Oh, und der Programmabruch mittels `sys.exit()` wird auch über eine Ausnahme realisiert, wenn man also alle Ausnahmen behandelt, sollte man sicherstellen, dass man damit nicht aus versehen das bewusste Beenden des Programms verhindert.
Re: PHP-Umsteiger braucht etwas Starthilfe ;)
Verfasst: Sonntag 24. Juni 2012, 15:21
von Malachite
BlackJack hat geschrieben:Der Sinn von `set_exception_handler()` erschliesst sich mir jetzt nicht wirklich. Wenn Du alle Ausnahmen abfangen willst — was man in der Regel gar nicht wollen sollte — kann man ein nacktes ``except:`` verwenden. Aber wie gesagt, davon sollte man Abstand nehmen, denn selten bis nie kann man an einer Stelle wirklich *alle* Ausnahmen *sinnvoll* behandeln, denn man weiss ja gar nicht welche das alle sein können. Und bei einigen wie zum Beispiel einem `MemoryError` weiss ich auch nicht wie man da sinnvoll weitermachen könnte wenn man ihn einfach ignoriert‽ Oh, und der Programmabruch mittels `sys.exit()` wird auch über eine Ausnahme realisiert, wenn man also alle Ausnahmen behandelt, sollte man sicherstellen, dass man damit nicht aus versehen das bewusste Beenden des Programms verhindert.
Ist in PHP wahrscheinlich sinnvoller, weil dort aus Kompatibilitätsgründen immer noch zwischen Fehlern und Exceptions unterschieden wird (wobei man das auch mit set_error_handler() und ErrorException ausgleichen kann.
Allerdings könnte man auch nur bestimmte Exceptions mit der Funktion behandeln und alle anderen einfach weiter werfen. Ich weiß nicht, ob das in Python möglich ist (gleich mal ausprobieren

), aber in PHP sähe das so aus:
Code: Alles auswählen
<?php
try {
throw new Exception("Lorem ipsum dolor sit amet!");
} catch (SomeException $exc) {
// Wird nicht ausgeführt, da eine Exception der Klasse "Exception" gefangen wird
} catch (AnotherException $exc) {
// Wird auch nicht ausgeführt
} catch ($exc) { // Jede Exception abfangen, die nicht in einem der vorherigen Blöcke abgefangen wurde
if ($exc instanceof SpecialException)
do_something_with($exc);
else
throw $exc; // Exception weiter werfen
}
?>
Oder in eine Handlerfunktion verpackt:
Code: Alles auswählen
<?php
set_exception_handler(
function($exc) {
if (($exc instanceof CustomException) || ($exc instanceof MyException)) {
echo $exc->doSomething(); // Exception behandeln
} else {
throw $exc; // Exception weiter werfen; wenn sie nicht gefangen wird, gibt es einen Fatal Error
}
}
);
?>
Oder man könnte jede Exception-Klasse gesondert behandeln:
Code: Alles auswählen
<?php
set_exception_handler(
function($exc) {
switch ($type = get_class($exc)) {
case 'ParseException':
echo "Parserfehler aufgetreten";
break;
case 'ErrorException':
echo "Exception gefangen, die eigentlich ein normaler Fehler sein sollte";
break;
default:
echo "Exception der Klasse ".$type." gefangen";
}
echo ": ".$exc->getMessage();
}
);
?>
Re: PHP-Umsteiger braucht etwas Starthilfe ;)
Verfasst: Sonntag 24. Juni 2012, 16:23
von BlackJack
@Malachite: Was ist denn der Sinn davon eine allgemeine Ausnahmebehandlung zu machen dort auf einen bestimmten Ausnahmetyp zu testen und in anderen Fällen die Ausnahme wieder auszulösen? Warum dann nicht gleich `SpecialException` so behandeln wie das *eigentlich* vorgesehen ist‽
Dein Beispiel würde in Python so aussehen:
Code: Alles auswählen
try:
raise MyException('Lorem ipsum dolor sit amet!')
except SomeException:
pass
except AnotherException:
pass
except Exception, exception:
if isinstance(exception, SpecialException):
do_something_with(exception)
else:
raise
Ich verstehe aber nicht warum Du es nicht so schreibst:
Code: Alles auswählen
try:
raise MyException('Lorem ipsum dolor sit amet!')
except SomeException:
pass
except AnotherException:
pass
except SpecialException, exception:
do_something_with(exception)
Das hat den gleichen Effekt, ist aber einfacher ausgedrückt und kommt ohne `isinstance()` aus.
Den Sinn von `set_exception_handler()` in normalen Programmen habe ich immer noch nicht verstanden. Das ist etwas was man in einer IDE oder einer interaktiven Programmierumgebung machen kann, aber doch nicht in normalen Programmen‽ Eine Ausnahme einfach auf der Konsole ausgeben und dann weitermachen als sei nichts passiert ist keine Fehlerbehandlung.
Wie sieht das bei der Funktion in PHP mit dem Gültigkeitsbereich aus? Wo greift dieser Handler? Global? Oder nur in der Funktion in der er gesetzt wurde und in draus ausgehenden Aufrufen? Wenn ersteres, dann ist das für normale Programme nahezu nutzlos, wenn letzteres sehe ich keinen Vorteil gegenüber der ``try``/``except``-Syntax. Kann es sein dass es global ist und bei PHP mehr Sinn macht, weil man da keine länger laufenden Programme hat, sondern etwas was nur einen Anfrage/Antwort-Zyklus lang „lebt”?
Re: PHP-Umsteiger braucht etwas Starthilfe ;)
Verfasst: Sonntag 24. Juni 2012, 16:56
von Malachite
War vielleicht etwas kompliziert ausgedrückt…
Was ich eigentlich meinte, ist, dass man mit set_exception_handler() einfach die Fehler zentral in einer Funktion behandeln kann, anstatt zig try-Blöcke im ganzen Programm zu verteilen und bei jeder Funktion zu überlegen: "Hm, was für Fehler könnten da auftreten? Wie behandle ich sie?" Stattdessen schreibt man eine Funktion, die bei einem Fehler einfach einspringt und ihn behandelt. Es geht nicht darum, das Programm in aller Ruhe weiter laufen zu lassen - natürlich kann die Funktion es auch beenden, je nachdem was für ein Fehler aufgetreten ist. So in der Art:
Code: Alles auswählen
def eh(exc):
if isinstance(exc,commonError):
print("Fehler ist aufgetreten")
elif issubclass(exc,parentOfAllEvil):
print("Schwerwiegender Fehler. Programm wird beendet")
sys.exit()
registerExceptionHandler(eh)
vulnerableFunction() # Löst commonError aus, Programm läuft trotzdem weiter
anotherVulnerableFunction() # Löst auch commonError aus
veryVulnerableFunction() #Löst eine Ausnahme aus, die ein Kind von parentOfAllEvil ist; Programm wird beendet
harmlessFunction() # Wird demzufolge nicht ausgeführt
anstatt:
Code: Alles auswählen
try:
vulnerableFunction()
except commonError:
print("Fehler ist aufgetreten!")
try:
anotherVulnerableFunction()
except commonError:
print("Fehler ist aufgetreten!")
try:
veryVulnerableFunction()
except parentOfAllEvil:
print("Schwerwiegender Fehler. Programm wird beendet.")
harmlessFunction()
Man spart sich eine Menge Tipparbeit (vor allem wenn man zig bis hunderte solcher fehleranfälligen Stellen hat), die Fehlerbehandlung erfolgt zentral… Was will man mehr?
Re: PHP-Umsteiger braucht etwas Starthilfe ;)
Verfasst: Sonntag 24. Juni 2012, 17:03
von Hyperion
Was spricht denn gegen:
Code: Alles auswählen
try:
vulnerableFunction()
anotherVulnerableFunction()
veryVulnerableFunction()
except commonError:
print("Fehler ist aufgetreten!")
except parentOfAllEvil:
print("Schwerwiegender Fehler. Programm wird beendet.")
harmlessFunction()
Das ist sogar noch weniger Tipparbeit und dafür hat man die kritischen Stellen auch gleich im Code "markiert" und *sieht* sofort, wo es zu Problemen kommen kann. Zudem musst Du den Fehler ja irgend wie behandeln - wenn Du das in eine Funktion verlagerst, hast Du ein Problem mit dem Namensraum
Im übrigen kann bei Deinem obigen Code `commonError` durchaus durchrutschen, sofern es sich ebenfalls um eine Subklasse von `parentOfAllEvil` handelt.
Klassennamen schreibt man übrigens eher CamelCase, also `CommonError`

Re: PHP-Umsteiger braucht etwas Starthilfe ;)
Verfasst: Sonntag 24. Juni 2012, 17:50
von BlackJack
@Malachite: Was Du suchst ist also eine einfache Möglichkeit zentral einzustellen, dass Ausnahmen auf magische Weise ignoriert werden. Also ohne das man an der entsprechenden Stelle sieht das eine Ausnahme zwar dokumentiert ist, aber anscheinend trotzdem nicht auftritt‽ Das klingt für mich ziemlich unsauber und fragil. Wie unterscheidet der Handler denn zwischen Code bei dem Du das möchtest und welchem, zum Beispiel aus der Standardbibliothek, bei dem die Ausnahmen dann auch ignoriert werden, und dadurch Fehler verschleiert und Folgefehler ausgelöst werden, oder einfach nur falsche Ergebnisse geliefert werden‽ In so einem Programm möchte ich nicht auf Fehlersuche gehen müssen. Das wäre ein Albtraum.
Wenn Ausnahmen auftreten können und das zum Beispiel an bestimmten Stellen auch dürfen, dann sollte man das an *der* Stelle im Quelltext deutlich lesen können und es nicht in einem globalen Handler verstecken. Ich würde zu so einem „Fehler ist aufgetreten” in der Regel auch einen Kommentar schreiben, der dem Leser des Quelltextes erklärt warum das nicht schlimm ist und ignoriert werden kann. Denn Fehler einfach in ein Textausgabe umzuwandeln und dann weiter zu machen als sei nichts gewesen ist ein „code smell”. Das ist im Allgemeinen keine angemessene Ausnahmebehandlung. Oder anders herum: Falls `commonError` hier bedeuten soll, dass es üblich ist, dass die Funktion diese Ausnahme auslöst, dann ist die Ausnahme im Wortsinn keine mehr und das Auslösen ist der eigentliche „code smell”.
@Hyperion: Das ist nicht äquivalent. Wenn `vulnerableFunction()` ausgeführt wurde und eine `commonError`-Ausnahme auslöst, dann wird bei Dir `anotherVulnerableFunction()` und `veryVulnerableFunction()` nicht mehr ausgeführt. Im Original aber schon!
Edit: Den speziellen Fall könnte man so schreiben:
Code: Alles auswählen
try:
for function in [
vulnerable_function,
another_vulnerable_function,
very_vulnerable_function,
harmless_function,
]:
try:
function()
except CommonError:
# The error can be ignored because...
print 'Fehler ist aufgetreten!'
except ParentOfAllEvil:
print 'Schwerwiegender Fehler. Programm wird beendet.'
sys.exit() # In case there is code below...
Re: PHP-Umsteiger braucht etwas Starthilfe ;)
Verfasst: Sonntag 24. Juni 2012, 17:54
von Hyperion
BlackJack hat geschrieben:
@Hyperion: Das ist nicht äquivalent. Wenn `vulnerableFunction()` ausgeführt wurde und eine `commonError`-Ausnahme auslöst, dann wird bei Dir `anotherVulnerableFunction()` und `veryVulnerableFunction()` nicht mehr ausgeführt. Im Original aber schon!
Stimmt. *face palm* Ich war zu sehr auf denselben Fehler fixiert

Re: PHP-Umsteiger braucht etwas Starthilfe ;)
Verfasst: Freitag 13. Juli 2012, 18:43
von Malachite
Aus der Python-Dokumentation:
sys.excepthook(type, value, traceback)
This function prints out a given traceback and exception to sys.stderr.
When an exception is raised and uncaught, the interpreter calls sys.excepthook with three arguments, the exception class, exception instance, and a traceback object. In an interactive session this happens just before control is returned to the prompt; in a Python program this happens just before the program exits. The handling of such top-level exceptions can be customized by assigning another three-argument function to sys.excepthook.
Ist jetzt vielleicht etwas spät, aber genau das habe ich gesucht. Da ein Traceback mitgeliefert wird, dürfte das mit dem Debugging auch kein großes Problem sein. Für mich ist sowas um einiges leserlicher als zig try/except/else/finally-Konstruktionen
Re: PHP-Umsteiger braucht etwas Starthilfe ;)
Verfasst: Freitag 13. Juli 2012, 18:50
von lunar
@Malachite: In einem guten Python-Programme solltest Du davon bis auf wenige Ausnahmen keinen Gebrauch machen. Python ist nicht PHP: In PHP braucht man diese Möglichkeit, weil es aufgrund des Ausführungsmodells von PHP keinen zentralen Einstiegspunkt gibt. In Python ist das nicht der Fall, es gibt fast immer einen Eintrittspunkt, also fange unbehandelte Ausnahmen dort ab, und zwar mit "try..except".
Re: PHP-Umsteiger braucht etwas Starthilfe ;)
Verfasst: Freitag 13. Juli 2012, 19:37
von BlackJack
@Malachite: Damit kannst Du einen Hook für die alleroberste Ebene setzen, also kurz bevor die Python-Laufzeitumgebung dir das Programm abbrechen würde. Wirklich sinnvoll kannst Du an der Stelle nichts mehr mit der Ausnahme anfangen, ausser vielleicht noch loggen und dann das Programm abbrechen. Du kannst das durch *ein* *einziges* ``try``/``except`` um das ganze Programm ersetzen. Also weiss ich nicht was Du denkst was Dir das bringen soll. Das hier:
Code: Alles auswählen
def my_excepthook(type_, value, traceback):
# do something...
sys.excepthook = my_excepthook
# entry point into program.
ist (nahezu) äquivalent zu
Code: Alles auswählen
try:
# entry point into program
except Exception, exception:
# do something...
nur ist letzteres weniger „magisch” weil es mit den dafür vorgesehenen Sprachmitteln auskommt.
Für Dein Beispiel mit `vulnerableFunction()`, `anotherVulnerableFunction()`, usw. kannst Du das jedenfalls nicht einsetzen weil Du dazu ja auch irgendwie wieder zurück in den Code kommen musst, bei dem die Ausnahme ausgelöst wurde um danach weiter machen zu können. Das geht aber nicht.
Re: PHP-Umsteiger braucht etwas Starthilfe ;)
Verfasst: Freitag 13. Juli 2012, 21:07
von Malachite
Für Dein Beispiel mit `vulnerableFunction()`, `anotherVulnerableFunction()`, usw. kannst Du das jedenfalls nicht einsetzen weil Du dazu ja auch irgendwie wieder zurück in den Code kommen musst, bei dem die Ausnahme ausgelöst wurde um danach weiter machen zu können. Das geht aber nicht.
Das habe ich auch gerade festgestellt. Ich habe halt gedacht, das funktioniert wie bei PHP: Eine Exception wird mit Stacktrace geworfen, der Interpreter schaut nach, ob das in einem try-Block passiert, wenn nicht, wird der Exception-Handler ausgeführt und danach wird das Programm fortgesetzt.

Re: PHP-Umsteiger braucht etwas Starthilfe ;)
Verfasst: Freitag 13. Juli 2012, 21:16
von BlackJack
@Malachite: Python ist nicht PHP. Damit meine ich nicht nur dass diese Funktion nicht so funktioniert wie Du das gedacht hast — wobei ich mir auch immer noch nicht vorstellen kann wie das überhaupt funktionieren soll — sondern dass die Probleme die Du damit glaubst zu lösen in Python ziemlich sicher nicht auftreten werden. Das gleiche gilt für die ganzen Fragen zu den Funktionen zur Typbestimmung am Anfang dieses Themas. Du suchst nach Lösungen zu Problemen die es so meiner Erfahrung nach nicht gibt.