Hallo!
Ich schreibe gerade an einer Art Mini-Wrapper, der Methoden aus der ftplib durch typische Unix-Befehle zugänglich machen soll. Das ganze läuft auf einer eigenen Shell und klappt in seiner bisherigen Form auch.
Jetzt möchte ich mich aber an die Fehlerbehandlung machen. Das ist mir schon allein für den persönlichen Gebrauch wichtig. Denn sobald ich irgendeinen Vertipper mache, werde ich komplett aus der Shell geworfen.
An dem gleich folgenden Skript kann man sehen, dass ich bisher den "Vertipper-Fehler" abfange und die Begründung ausgebe. Natürlich könnte ich jetzt direkt in allen vorhandenen (und möglicherweise folgenden) do_*-Funktionen den selben Fehler abfangen - dann würde er mich nicht rausschmeissen. Aber gibt es nichts eleganteres als die ständige Wiederholung des try-except-Blocks? Mag auch sein, dass ich mich gerade etwas dumm anstelle. Helft mir bitte auf die Sprünge.
http://paste.pocoo.org/show/104011/
Fehlerbehandlung beim Modul "cmd"
Evtl mit nem decorator?
Code: Alles auswählen
def catch_ftp_errors(func):
def catch(*args, **kwargs):
try:
func(*args, **kwargs)
except ftplib....: pass
return catch
...
@catch_ftp_errors
def do_...
Wenns bissi Metaklassen Magie sein soll (ja, ich selbst zweifle auch die Sinnhaftigkeit des Folgenden an).
Code: Alles auswählen
def dec(f):
def exc(*args, **kwargs):
# Hier dein error handling rein.
print 'foo'
return f(*args, **kwargs)
return exc
def metacls(name, bases, dict_):
for key, value in dict_.iteritems():
if hasattr(value, '__call__'):
dict_[key] = dec(value)
return type(name, bases, dict_)
class Foo(object):
__metaclass__ = metacls
def x(self):
pass
foo = Foo()
foo.x()
Ohloh | Mein Blog | Jabber: segfaulthunter@swissjabber.eu | asynchia – asynchrone Netzwerkbibliothek
In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.
In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.
Besten Dank. Mit Dekoratoren war ich noch nicht so vertraut, aber jetzt funktioniert es.
http://paste.pocoo.org/show/104053/
http://paste.pocoo.org/show/104053/
Oha. Sofern das nicht irgendwelche phänomenalen Vorteile in meinem Fall bringt, würde ich doch eher Dekoratoren bevorzugen.name hat geschrieben:Wenns bissi Metaklassen Magie sein soll (ja, ich selbst zweifle auch die Sinnhaftigkeit des Folgenden an).
Zuletzt geändert von snafu am Sonntag 15. Februar 2009, 00:47, insgesamt 2-mal geändert.
Warum machst du nicht statt das hier:
Code: Alles auswählen
if hasattr(value, '__call__'):
Code: Alles auswählen
if callable(value):
Und für Metaklassen sollte man auch wirklich eine Klasse verwenden und nicht eine Funktion Es wäre in diesem Fall nur eine Zeile länger, aber sieht etwas besser was passiert.
Die Dekorator-Lösung halte ich hier auch für die richtige Wahl. Man kann natürlich auf den Dekoratoren noch mit Metaklassen rumspielen
Die Dekorator-Lösung halte ich hier auch für die richtige Wahl. Man kann natürlich auf den Dekoratoren noch mit Metaklassen rumspielen
Zuletzt geändert von EyDu am Sonntag 15. Februar 2009, 00:25, insgesamt 2-mal geändert.
Das Leben ist wie ein Tennisball.
Weil das mit 3.0 gehen muss.derdon hat geschrieben:Warum machst du nicht stattdas hier:Code: Alles auswählen
if hasattr(value, '__call__'):
Code: Alles auswählen
if callable(value):
Ich zitiere:EyDu hat geschrieben:Und für Metaklassen sollte man auch wirklich eine Klasse verwenden und nicht eine Funktion Es wäre in diesem Fall nur eine Zeile länger, aber sieht etwas besser was passiert.
Die Dekorator-Lösung halte ich hier auch für die richtige Wahl. Man kann natürlich auf den Dekoratoren noch mit Metaklassen rumspielen
Also wozu eine Klasse wenn man sie nicht braucht (Das ist hier ja kein Java)? Die Metaklasse ist dann halt immer noch type.__metaclass__
This variable can be any callable accepting arguments for name, bases, and dict. Upon class creation, the callable is used instead of the built-in type().
Ohloh | Mein Blog | Jabber: segfaulthunter@swissjabber.eu | asynchia – asynchrone Netzwerkbibliothek
In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.
In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.
Steht wo? callable sollte automatisch nach 3.0 konvertiert werden können, andererseits hat nicht jedes callable unter 2.5/(6?) __call__. Also muss man callable verwenden.name hat geschrieben:Weil das mit 3.0 gehen muss.derdon hat geschrieben:Warum machst du nicht stattdas hier:Code: Alles auswählen
if hasattr(value, '__call__'):
Code: Alles auswählen
if callable(value):
Welche Funktion hat es denn nicht? Und hier brauchen wir ja eigtl. nur Funktionen. o_ODarii hat geschrieben:Steht wo? callable sollte automatisch nach 3.0 konvertiert werden können, andererseits hat nicht jedes callable unter 2.5/(6?) __call__. Also muss man callable verwenden.name hat geschrieben:Weil das mit 3.0 gehen muss.derdon hat geschrieben:Warum machst du nicht stattdas hier:Code: Alles auswählen
if hasattr(value, '__call__'):
Code: Alles auswählen
if callable(value):
Ohloh | Mein Blog | Jabber: segfaulthunter@swissjabber.eu | asynchia – asynchrone Netzwerkbibliothek
In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.
In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.
Darii hat geschrieben:callable sollte automatisch nach 3.0 konvertiert werden können[...]
Code: Alles auswählen
bash-3.2$ cat foo.py
callable(lambda: None)
bash-3.2$ python -3 foo.py
foo.py:1: DeprecationWarning: callable() not supported in 3.x; use hasattr(o, '__call__')
callable(lambda: None)
Das betrifft "old-style"-Klassen. "New-style"-Klassen haben das Attribut:
Code: Alles auswählen
In [56]: class A(object): pass
....:
In [57]: A.__call__
Out[57]: <method-wrapper '__call__' of type object at 0x8d2b664>
Im Grunde ist diese Funktion ein Dekorator für Klassen, der für jedes aufrufbare Objekt wieder eine Dekorator Funktion auf dieses Objekt anwendet. Metaklassen an sich sind deutlich mächtiger. (Mit 3.0 gibt es auch "richtige" Dekoratoren für Klassen - Mag es sein, das mit einer solchen "Metafunktion" die Funktionalität im Grunde auch implementiert werden kann? Sieht danach aus.)Oha. Sofern das nicht irgendwelche phänomenalen Vorteile in meinem Fall bringt, würde ich doch eher Dekoratoren bevorzugen. Wink
Ich habe das ganze nun nochmal direkt mithilfe einer "Metafunktion" umgeschrieben, sieht dann so aus:
http://dpaste.com/120954/
(paste.pocoo.org ist down)
Da ich noch 2.5 verwende, musste ich nur unten meinen eigenen methodcaller bauen (was ich auch ohne getattr hätte machen können, aber nun ist es gepostet). Man kann also praktisch schon in 2.5 solche Pseudoklassendekoratoren benutzen, der einzige Unterschied ist, daß ein echter Dekorator die Klasse nach der Konstruktion bekommt, während ein solcher Pseudodekorator die Klasse zusammengebaut zurückliefern musst. Darum gings mir ja, man kann es praktisch 1:1 umschreiben.
http://dpaste.com/120954/
(paste.pocoo.org ist down)
Da ich noch 2.5 verwende, musste ich nur unten meinen eigenen methodcaller bauen (was ich auch ohne getattr hätte machen können, aber nun ist es gepostet). Man kann also praktisch schon in 2.5 solche Pseudoklassendekoratoren benutzen, der einzige Unterschied ist, daß ein echter Dekorator die Klasse nach der Konstruktion bekommt, während ein solcher Pseudodekorator die Klasse zusammengebaut zurückliefern musst. Darum gings mir ja, man kann es praktisch 1:1 umschreiben.
-
- User
- Beiträge: 155
- Registriert: Freitag 29. Dezember 2006, 18:27
Wenn ich dein Problem richtig verstehe, könntest du auch einfach die Methode `onecmd` überschreiben. Orientiere dich einfach an dem Original in cmd.py und füg das Exceptionhandling hinzu.
Gruß,
Fred
Gruß,
Fred
Dann würde ich den bisherigen Code der Methode übernehmen und lediglich die Zeilen für's Errorhandling einfügen. Ich finde die Abtrennung der Aufgaben mittels eigener Funktion schon besser, ehrlich gesagt. Wenn man sich den Docstring anschaut, steht da auch, dass es erstmal nur um die Interpretation der Eingabe geht. Ich will da nicht so sehr in den internen Ablauf des Moduls eingreifen, wenn es auch anders geht. Zudem wird sowas schnell unübersichtlich.fred.reichbier hat geschrieben:Wenn ich dein Problem richtig verstehe, könntest du auch einfach die Methode `onecmd` überschreiben. Orientiere dich einfach an dem Original in cmd.py und füg das Exceptionhandling hinzu.
Das Problem - um es nochmal deutlich zu machen - steht im Ablauf hinter der do_*-Funktion und somit hinter der Interpretation. Es ging darum, innerhalb des Loops eine Unterbrechung durch Exception zu vermeiden, also quasi eine Art Überwachungsinstanz einzurichten, die im Fall der Fälle eingreifen kann. Das Konzept von Dekoratoren eignet sich dafür IMHO am besten.