Frage

Ich habe eine Liste, die eine Liste filtert:

l = [obj for obj in objlist if not obj.mycond()]

Aber die Objektmethode mycond () kann eine Ausnahme anstellen, die ich abfangen muss. Ich muss alle Fehler am Ende der Schleife sammeln, um zu zeigen, welches Objekt Probleme erzeugt hat, und gleichzeitig möchte ich sicher sein, dass Sie alle Listenelemente schleifen.

Meine Lösung war:

errors = []
copy = objlist[:]

for obj in copy:
    try:
        if (obj.mycond()):
            # avoiding to touch the list in the loop directly
            objlist.remove(obj) 
    except MyException as err:
        errors = [err]
if (errors):
   #do something

return objlist

In diesem Beitrag (So löschen Sie Listenelemente beim Radfahren der Liste selbst, ohne sie zu doppelten) Ich frage, ob es eine bessere Methode gibt, um das Duplikat der Liste zu vermeiden.

Die Community antwortet mir, um die Änderung der Liste zu vermeiden und eine Liste zu verwenden, die anwendbar ist, wenn ich das Ausnahmeproblem ignoriere.

Gibt es eine alternative Lösung in Ihrer Sicht? Kann ich die Ausnahme auf diese Weise mithilfe von Listenverständnissen verwalten? In dieser Art von Situation und Verwendung großer Listen (was ich für groß halten muss) muss ich eine andere Alternative finden?

War es hilfreich?

Lösung

Ich würde eine kleine Hilfsfunktion verwenden:

def f(obj, errs):
  try: return not obj.mycond()
  except MyException as err: errs.append((obj, err))

errs = []
l = [obj for obj in objlist if f(obj, errs)]
if errs:
  emiterrorinfo(errs)

Beachten Sie, dass Sie auf diese Weise in errs Alle fehlerhaften Objekte und Die spezifische Ausnahme, die jeder von ihnen entspricht, sodass die Diagnose präzise und vollständig sein kann. ebenso wie l Sie benötigen und Ihre objlist Immer noch intakt für eine mögliche weitere Verwendung. Es wurde keine Listenkopie benötigt, noch Änderungen an objDie Klasse des Codes ist sehr einfach.

Andere Tipps

Ein paar Kommentare:

Zunächst die Listenverständnissyntax [expression for var in iterable] Erstellt eine Kopie. Wenn Sie keine Kopie der Liste erstellen möchten, verwenden Sie den Generatorausdruck (expression for var in iterable).

Wie arbeiten Generatoren? Im Wesentlichen durch Anruf next(obj) auf dem Objekt wiederholt bis a GeneratorExit Ausnahme wird erhöht.

Basierend auf Ihrem ursprünglichen Code scheint es, dass Sie die gefilterte Liste noch als Ausgabe benötigen.

So können Sie das mit wenig Leistungsverlust nachahmen:

l = []
for obj in objlist:
   try:
      if not obj.mycond()
         l.append(obj)
   except Exception:
      pass

Sie können diese alle mit einer Generatorfunktion überarbeiten:

def FilterObj(objlist):
   for obj in objlist:
      try:
         if not obj.mycond()
            yield obj
      except Exception:
         pass

Auf diese Weise können Sie in der Zwischenzeit sicher über sie eingehen, ohne eine Liste zwischenzuspeichern:

for obj in FilterObj(objlist):
   obj.whatever()

Sie könnten eine Methode von OBJ definieren, die obj.mycond () nennt, aber auch die Ausnahme fängt

class obj:

    def __init__(self):
        self.errors = []

    def mycond(self):
        #whatever you have here

    def errorcatcher():
        try:
            return self.mycond()
        except MyException as err:
            self.errors.append(err)
            return False # or true, depending upon what you want

l = [obj for obj in objlist if not obj.errorcatcher()]

errors = [obj.errors for obj in objlist if obj.errors]

if errors:
    #do something

Anstatt die Liste zu kopieren und Elemente zu entfernen, beginnen Sie mit einer leeren Liste und fügen Sie bei Bedarf die Mitglieder hinzu. Etwas wie das:

errors = []
newlist = []

for obj in objlist:
    try:
        if not obj.mycond():
            newlist.append(obj)
    except MyException as err:
        errors.append(err)
if (errors):
   #do something

return newlist

Die Syntax ist nicht so hübsch, aber es wird mehr oder weniger das Gleiche tun, was das Listenverständnis ohne unnötige Umzugungen tut.

Das Hinzufügen oder Entfernen von Elementen zu oder von irgendwo anders als am Ende einer Liste ist langsam, denn wenn Sie etwas entfernen, muss dies erforderlich sein Gehen Sie jedes Element durch, das nach ihm kommt, und subtrahieren Sie einen von seinem Index, und das gleiche, um etwas hinzuzufügen, außer dass es dem Index hinzufügen muss. Aktualisieren Sie die Position aller Elemente danach.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top