Designfrage: Von list ableiten?
Hallo, ich habe eine Klasse JobQueue, die eigentlich eine Liste mit ein paar zusätzlichen Methoden ist: Voreinstellung fürs Sortieren: def sort(self, reverse = False): """ Sort by priority """ self._queue.sort(key = lambda a: a.prio, reverse=reverse) Hinzufügen: def put(self, job): job.jid = gen_jid() self._queue.append(j) return job.jid filtern: def running_jobs(self): self.sort() return [job for job in self._queue if job.running] usw. Also nichts großartiges. Der Benutzer der Klasse soll auch problemlos an die verwaltete Liste selber kommen (hier self._queue). Spricht nun irgendwas dagegen die Klasse von list abzuleiten und selber eine Liste zu sein? Damit das Verhalten möglichst wenig beeinflußt wird, würde ich sort so schreiben: def sort(self, key = lambda a: a.prio, reverse = False): """ Sort by priority """ super(JobQueue, self).sort(key, reverse) (geht das? Einen lambda Ausdruck als default Argument?) Da ich für alle neuen Jobs in der Queue selber eine ID generiere (siehe put()) muss/würde ich gerne garantieren, dass das für alle neu hinzugefügten ebenso ist. Reicht es dafür append() zu überschreiben? Effizienz spielt bei der ganzen Sache keine Rolle, die jeweiligen Jobs haben Rechenzeiten von 1 bis mehreren Tagen, da tut sich nicht viel... ;-) Mich würde es interessieren, ob es da noch irgendwelche versteckten Probleme gibt? Und was prinzipiell Eure Meinung dazu ist. Grüße, Florian
Hallo Florian, On 2011-06-12 23:29, Florian Lindner wrote:
ich habe eine Klasse JobQueue, die eigentlich eine Liste mit ein paar zusätzlichen Methoden ist:
Voreinstellung fürs Sortieren:
def sort(self, reverse = False): """ Sort by priority """ self._queue.sort(key = lambda a: a.prio, reverse=reverse)
Hinzufügen:
def put(self, job): job.jid = gen_jid() self._queue.append(j) return job.jid
filtern:
def running_jobs(self): self.sort() return [job for job in self._queue if job.running]
usw. Also nichts großartiges. Der Benutzer der Klasse soll auch problemlos an die verwaltete Liste selber kommen (hier self._queue).
warum hat das Attribut dann einen führenden Unterstrich? ;-) Der sagt per Konvention aus, dass etwas ein nicht-öffentliches Implementierungsmerkmal ist.
Spricht nun irgendwas dagegen die Klasse von list abzuleiten und selber eine Liste zu sein?
Ich würde es eher nicht tun. Jedenfalls nicht, um nur Implementierungs-Aufwand zu sparen. Das kannst du auch mit __getattr__ erreichen, indem du _bestimmte_ Zugriffe an das enthaltene Listen-Attribut "durchreichst". Wenn es nur wenige Attribute sind (vgl. unten), würde ich allerdings kein __getattr__ verwenden. Wenn du deine Klasse von list ableiten lässt, legt das nahe, dass deine Klasse nicht nur technisch, sondern auch sinngemäß eine Python-Liste - mit allen ihrer Eigenarten - ist. Ist es zum Beispiel sinnvoll, in eine _Queue_ Werte mit "insert" oder Slicing mittendrin einzufügen? Ich denke nicht. :-) Spätestens, wenn eine Listen-Methode einer deiner Methoden "widerspricht", hast du ein Problem. Ich würde von einer Python-Liste zum Beispiel nicht erwarten, dass die darin enthaltenen Elemente ein prio(rity)-Attribut haben müssen, wenn ich die sort-Methode aufrufe. Und das betrifft ja sogar schon eine der von dir aufgeführte Methode und nicht eine "beiläufig" von list geerbte. Ganz entsprechend würde ich auch die enthaltene Liste als Implementierungs-Detail ansehen und Anwendern deiner Klasse auch vom direkten Zugriff abraten. Der führende Unterstrich vermittelt das ja auch und sollte demnach bleiben.
Damit das Verhalten möglichst wenig beeinflußt wird, würde ich sort so schreiben:
def sort(self, key = lambda a: a.prio, reverse = False): """ Sort by priority """ super(JobQueue, self).sort(key, reverse)
(geht das? Einen lambda Ausdruck als default Argument?)
Technisch gesehen ist das möglich, aber ich finde es eher unübersichtlich. Ich würde die Funktion, die als Default-Argument dienen soll, eher vorher definieren: class JobQueue(object): @staticmethod def _priority_key(key): return key.priority ... def sort(self, key=_priority_key, reverse=False): ... Das lässt sich meines Erachtens deutlich besser lesen, auch, wenn der Unterstrich nach dem Gleichheitszeichen ein bisschen seltsam aussieht.
Mich würde es interessieren, ob es da noch irgendwelche versteckten Probleme gibt? Und was prinzipiell Eure Meinung dazu ist.
Ich tendiere dazu, im Zweifelsfall die Schnittstelle möglichst schlank zu halten. Je weniger Versprechen man macht, desto einfacher ist es normalerweise, diese einzuhalten. :-) Beliebig einfach geht's natürlich auch nicht, denn schließlich möchte man dem Aufrufer ja eine Funktionalität anbieten, damit dieser diese nicht selbst implementieren muss. Viele Grüße Stefan
participants (2)
-
Florian Lindner
-
Stefan Schwarzer