Von file geerbt

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.
Antworten
HarryH
User
Beiträge: 266
Registriert: Freitag 23. Mai 2003, 09:08
Wohnort: Deutschland

Donnerstag 23. Juli 2009, 08:26

Hallo,

Habe mir eine kleine Klasse geschrieben die von file erbt. In dieser Klasse habe ich eine Progress-Funktionalität eingebaut, z.B. zur Realisierung von Fortschrittsanzeigen.
An mein file-object kann nun eine progress Funktion übergeben werden, die ein Argument empfängt, nämlich die geschriebene Buffer-Länge. Innerhalb dieser Funktion kann dann z.B. eine Fortschrittsanzeige angetrieben werden.

Nun würde ich gerne eure Meinung dazu wissen. Ist das korrekt so wie ich das mache?

Hier nun die Klasse:

Code: Alles auswählen

class MyFile(file):
    """Special file object, with progress functionality"""
    stdwrite = file.write
    stdread = file.read

    def __init__(self, filename, mode='r', bufsize=-1, progress_func=None):
        file.__init__(self, filename, mode, bufsize)
        self.progress_func = progress_func
        
    def write(self, s):
        self.stdwrite(s)
        # call progress function
        buflen = len(s)
        self.progress_func and buflen and self.progress_func(value=buflen)

    def read(self, size=-1):
        s = self.stdread(size)
        # call progress function
        buflen = len(s)
        self.progress_func and buflen and self.progress_func(value=buflen)
        return s
Gruß, Harry
Benutzeravatar
veers
User
Beiträge: 1219
Registriert: Mittwoch 28. Februar 2007, 20:01
Wohnort: Zürich (CH)
Kontaktdaten:

Donnerstag 23. Juli 2009, 09:09

Das sieht für mich Gefährlich aus. Wenn file.writelines verwendet wird tut das zum Beispiel nicht. Wenn du das anders lösen kannst dann würde ich das anders lösen. ;)

Gruss,
Jonas
[url=http://29a.ch/]My Website - 29a.ch[/url]
"If privacy is outlawed, only outlaws will have privacy." - Phil Zimmermann
Benutzeravatar
snafu
User
Beiträge: 6072
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Donnerstag 23. Juli 2009, 09:26

Mal von dem Sinn der ganzen Klasse abgesehen, frage ich mich, warum `progress_func` ein Keyword-Argument ist. Die sind ja eher dafür gedacht, dass man Vorgaben übernimmt, wenn man nichts anderes will. Ich wüsste aber nicht, wie die Klasse funktionieren soll, wenn sie `None` erhält...
BlackJack

Donnerstag 23. Juli 2009, 09:27

@HarryH: Der Name der Klasse ist etwas unspezifisch.

Die bedingte Ausführung mit ``and`` statt mit einem ordentlichen ``if`` ist in Python unüblich.

Ich würde auch die "Sonderfälle" eliminieren, oder zumindest dokumentieren warum die Default-Rückruffunktion `None` ist und warum `stdwrite` und `stdread` auf Klassenebene definiert werden. Ich würd's erst einmal anders machen bis ich wirklich gemessen habe, dass das zu langsam ist. Kann natürlich sein, dass Du das schon getan hast.

Du zwingst den Benutzer der Klasse das Argument der Rückruffunktion `value` zu nennen. Warum?

Code: Alles auswählen

class MyFile(file):
    """Special file object, with progress functionality"""

    def __init__(self,
                 filename,
                 mode='r',
                 bufsize=-1,
                 progress_func=lambda data_size: None):
        file.__init__(self, filename, mode, bufsize)
        self.progress_func = progress_func
    
    def write(self, data):
        if data:
            file.write(self, data)
            self.progress_func(len(data))

    def read(self, size=-1):
        result = file.read(self, size)
        self.progress_func(len(result))
        return result
Letztlich sollte man sich aber gut überlegen, ob man von `file` erben möchte und nicht lieber eine Proxy-Klasse schreibt, denn beim Erben von `file` muss man auf jeden Fall auch noch dokumentieren was alles nicht funktioniert! `file.readline()` oder das Iterieren über die Datei gehen zum Beispiel an diesen beiden Methoden vorbei. Und man wäre mit einem Proxy auch flexibler, weil man zum Beispiel dort auch andere "file like"-Objekte reinstecken kann, beispielsweise das was `urllib.urlopen()` zurück gibt.
Benutzeravatar
snafu
User
Beiträge: 6072
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Donnerstag 23. Juli 2009, 09:33

Ich würde wie gesagt eher zu garkeinem Keyword-Argument tendieren, als zu einem Lambda-Konstrukt, welches das Argument verschluckt. Oder übersehe ich hier irgendwelche Vorteile?
BlackJack

Donnerstag 23. Juli 2009, 10:07

@snafu: Ich verstehe gerade nicht was Du mit Keyword-Argument meinst!? Und wie würdest Du das anders lösen?
Benutzeravatar
snafu
User
Beiträge: 6072
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Donnerstag 23. Juli 2009, 10:50

Code: Alles auswählen

def __init__(self, filename, progress_func, mode='r', bufsize=-1)
oder, wenn man den vorherigen Konstruktor behalten will:

Code: Alles auswählen

if self.progress_func:
    self.progress_func(len(data))
Ich verstehe halt nicht, was der Umweg über Lambda bringen soll.
BlackJack

Donnerstag 23. Juli 2009, 11:16

@snafu: Der eleminiert den Sonderfall, den Du mit dem ``if`` prüfst und dient gleichzeitig als Dokumentation. Man weiss dann das da eine Funktion erwartet wird, die ein Argument entgegennimmt und wenn das halbwegs passend benannt ist, ist das auch nochmal "Doku".

Ich mags halt nicht, wenn ich an allen Ecken und Enden prüfen muss, ob etwas `None` ist, wenn ich an *einer* Stelle dafür sorgen kann, dass es mit einem Wert initialisiert wird, der einfach so verwendet werden kann.
HarryH
User
Beiträge: 266
Registriert: Freitag 23. Mai 2003, 09:08
Wohnort: Deutschland

Donnerstag 23. Juli 2009, 12:15

Hallo an alle,

Vielen Dank für eure nützlichen Anregungen!

@BlackJack: Das mit der lamba funktion ist ein guter Tip. Ich spare mir dann die Prüfung innerhalb der Methoden und es dient der Doku.

Das mit dem Argument 'value' hat sich so aus meiner individuellen Anwendung der Funktion ergeben. Habe es schon geändert; ist wirklich unnötig.
Die Geschwindigkeit habe ich allerdings noch nicht gemessen.

Bseonders interessant fand ich

Code: Alles auswählen

file.write(self, data)
file.read(self, size)
anstelle meiner

Code: Alles auswählen

stdwrite = file.write
stdread = file.read
Das hatte mich nämlich am meisten gestört. Ich wußte nur nicht das es auch besser geht.
Gruß, Harry
Antworten