Angenommen, Code wie folgt:
class Base:
def start(self):
pass
def stop(self)
pass
class A(Base):
def start(self):
... do something for A
def stop(self)
.... do something for A
class B(Base):
def start(self):
def stop(self):
a1 = A(); a2 = A()
b1 = B(); b2 = B()
all = [a1, b1, b2, a2,.....]
Jetzt möchte ich Methoden start und stop (vielleicht auch andere) für jedes Objekt in der Liste all aufrufen. Gibt es eine elegante Möglichkeit, dies zu tun, außer eine Reihe von Funktionen wie zu schreiben?
def start_all(all):
for item in all:
item.start()
def stop_all(all):
Base
mit nutzlosen Methoden und definieren dann das Verhalten in PythonA
undB
spiegeln ein schlechtes Design wider. Anstatt eine abstrakte Basisklasse zu verwenden, können Sie sie einfach definierenA
undB
austauschbar verwenden, sofern sie eine Schnittstelle gemeinsam nutzen. Ihre derzeitige Vorgehensweise schafft eine nutzlose Klasse, die nur zusätzliche Dinge sind, die Sie nicht benötigen.Antworten:
Die * _all () -Funktionen sind so einfach, dass ich für einige Methoden nur die Funktionen schreiben würde. Wenn Sie viele identische Funktionen haben, können Sie eine generische Funktion schreiben:
def apply_on_all(seq, method, *args, **kwargs): for obj in seq: getattr(obj, method)(*args, **kwargs)
Oder erstellen Sie eine Funktionsfactory:
def create_all_applier(method, doc=None): def on_all(seq, *args, **kwargs): for obj in seq: getattr(obj, method)(*args, **kwargs) on_all.__doc__ = doc return on_all start_all = create_all_applier('start', "Start all instances") stop_all = create_all_applier('stop', "Stop all instances") ...
quelle
Das wird funktionieren
all = [a1, b1, b2, a2,.....] map(lambda x: x.start(),all)
einfaches Beispiel
all = ["MILK","BREAD","EGGS"] map(lambda x:x.lower(),all) >>>['milk','bread','eggs']
und in python3
all = ["MILK","BREAD","EGGS"] list(map(lambda x:x.lower(),all)) >>>['milk','bread','eggs']
quelle
map()
Funktionsaufruf nicht aus. Es wird ein Generatorobjekt erstellt, aber kein Lambda auf jedes Listenelement angewendet. Lambda wird beim Durchlaufen des map () - Ergebnisses angewendet.list(map(...))
wird das Problem beheben.[x.start() for x in all]
?for
Schleife idiomatischer und für den Leser weniger überraschend. Wenn Sie wirklich müssen, könnten Sie schreibendef foreach(fun, gen): for i in gen: fun(gen)
.Es scheint, als gäbe es einen pythonischeren Weg, dies zu tun, aber ich habe ihn noch nicht gefunden.
Ich verwende manchmal "map", wenn ich dieselbe Funktion (keine Methode) für eine Reihe von Objekten aufrufe:
Dies ersetzt eine Reihe von Code, der folgendermaßen aussieht:
Kann aber auch mit einer Fußgängerschleife "for" erreicht werden:
for obj in a_list_of_objects: do_something(obj)
Der Nachteil ist, dass a) Sie eine Liste als Rückgabewert aus "map" erstellen, die gerade weggeworfen wird, und b) es möglicherweise verwirrender ist als nur die einfache Schleifenvariante.
Sie könnten auch ein Listenverständnis verwenden, aber das ist auch ein bisschen missbräuchlich (noch einmal, eine Wegwerfliste erstellen):
[ do_something(x) for x in a_list_of_objects ]
Für Methoden würde wohl eine dieser Methoden funktionieren (mit den gleichen Vorbehalten):
map(lambda x: x.method_call(), a_list_of_objects)
oder
[ x.method_call() for x in a_list_of_objects ]
In Wirklichkeit denke ich, dass die "for" -Schleife für Fußgänger (und dennoch effektiv) wahrscheinlich die beste Wahl ist.
quelle
mapcar
undmapc
um zwischen den Fällen "Liste wollen / Liste wegwerfen" zu unterscheiden. Aber leider ...Die Vorgehensweise
for item in all: item.start()
ist einfach, leicht, lesbar und prägnant. Dies ist der Hauptansatz, den Python für diese Operation bereitstellt. Sie können es sicherlich in eine Funktion einkapseln, wenn das etwas hilft. Das Definieren einer speziellen Funktion für den allgemeinen Gebrauch ist wahrscheinlich weniger klar als nur das Ausschreiben der for-Schleife.
quelle
Vielleicht
map
, aber da Sie keine Liste erstellen möchten, können Sie Ihre eigene schreiben ...def call_for_all(f, seq): for i in seq: f(i)
dann können Sie tun:
Übrigens ist alles eine eingebaute Funktion, überschreibe sie nicht ;-)
quelle
Ab Python 2.6 gibt es eine operator.methodcaller- Funktion.
So können Sie etwas eleganteres (und schnelleres) erhalten:
from operator import methodcaller map(methodcaller('method_name'), list_of_objects)
quelle
map
ein Iterator in 3 zurückgegeben wird, keine ListeWenn Sie die Antwort von @Ants Aasmas noch einen Schritt weiter gehen, können Sie einen Wrapper erstellen, der jeden Methodenaufruf akzeptiert und an alle Elemente einer bestimmten Liste weiterleitet:
class AllOf: def __init__(self, elements): self.elements = elements def __getattr__(self, attr): def on_all(*args, **kwargs): for obj in self.elements: getattr(obj, attr)(*args, **kwargs) return on_all
Diese Klasse kann dann folgendermaßen verwendet werden:
class Foo: def __init__(self, val="quux!"): self.val = val def foo(self): print "foo: " + self.val a = [ Foo("foo"), Foo("bar"), Foo()] AllOf(a).foo()
Welches erzeugt die folgende Ausgabe:
Mit etwas Arbeit und Einfallsreichtum könnte es wahrscheinlich erweitert werden, um auch Attribute zu verarbeiten (Rückgabe einer Liste von Attributwerten).
quelle