Seite 1 von 1

__iter__ ohne yield

Verfasst: Donnerstag 12. Februar 2009, 10:19
von Mad-Marty
Hi,

wenn ein object in seiner __iter__ nur ein raise StopIteration() hat ... wird dies als normale Exception nach oben durchgereicht.

Erst mit einem Dummy-yield funktioniert es wie gewünscht.
Muss die __iter__ method als Generator (durch yield) definiert sein?

Wie erreiche ich das Verhalten des unteren Dummys ohne das Hässliche 'if'?

Dieses Object lässt sich nicht iterieren ohne Exception

Code: Alles auswählen

class Dummy(object):
   def __iter__(self):
      raise StopIteration("dummy intended not to iterate")
Dieses hingegen schon:

Code: Alles auswählen

class Dummy(object):
   def __iter__(self):
      if False:
         yield True
      raise StopIteration("dummy intended not to iterate")

Re: __iter__ ohne yield

Verfasst: Donnerstag 12. Februar 2009, 10:26
von Leonidas
Mad-Marty hat geschrieben:Muss die __iter__ method als Generator (durch yield) definiert sein?
Nein, sie muss aber einen Iterator zurückgeben. Du hast schon recht, eine ``StopIteration`` wäre logisch, aber die ist wie du siehst nur in Generatoren nützlich.

Meine Lösung ohne ein ``if`` sähe so aus:

Code: Alles auswählen

class Dummy(object):
    def __iter__(self):
        return iter(list())
Persönlich finde ich die leere Liste nicht so gut gelungen, aber normalerweise macht man Objekte nicht-``iterable`` indem man ``__iter__`` schlicht nicht definiert ;)

Verfasst: Donnerstag 12. Februar 2009, 10:38
von Mad-Marty
Persönlich finde ich die leere Liste nicht so gut gelungen, aber normalerweise macht man Objekte nicht-``iterable`` indem man ``__iter__`` schlicht nicht definiert Wink
Naja ich finde Objekte sollten (sofern sinnvoll), schon iterierbar sein, einfach weil es sich super in die Sprache integriert.

(Und der Dummy ist mehr fürs Testen in dem Fall).

Verfasst: Donnerstag 12. Februar 2009, 10:40
von Leonidas
Mad-Marty hat geschrieben:Naja ich finde Objekte sollten (sofern sinnvoll), schon iterierbar sein, einfach weil es sich super in die Sprache integriert.
Ja, aber wenn du das iterieren durch so Tricks "abschalten" willst, klingt es so als würde es eben nicht sinnvoll sein über dieses Objekt zu iterieren.
Aber das ist natürlich schwer abzuschätzen, wenn man deinen Code nicht kennt.

Verfasst: Donnerstag 12. Februar 2009, 12:40
von Mad-Marty
Eine Factory verarbeitet empfangene Daten zu unterschiedlichen datensets.
Es wird explizit damit gerechnet das manche daten nicht konvertiert oder verwendet werden können.

Die empfangenen Daten sind sofern richtig, iterierbar bzw generatoren.
Für ungültige Daten muss auch ein Dummy objekt her, was bei verwendung eben nichts iteriert (da keine gültigen Daten) und somit eben nur ein paar counter und stats erhöht.

Es soll also bewusst keine Exceptions geben bei ungültigen Daten und diese Datensätze sollen sich in der weiteren chain verhalten wie gültige in bezug auf statistik, allerdings eben keinen verwendbaren inhalt anbieten bei iteration.

Verfasst: Donnerstag 12. Februar 2009, 13:05
von Leonidas
Ok, das scheint mehr oder weniger ok zu sein. Nunja, eine funktionierende Lösung ist oben gepostet, was wesentlich eleganteres fällt mir nicht mehr ein :)

Verfasst: Donnerstag 12. Februar 2009, 17:11
von str1442

Code: Alles auswählen

class NotIterable(object):
     def next(self):
          raise StopIteration()

class Dummy(object):
     def __iter__(self):
          return NotIterable()

Verfasst: Donnerstag 12. Februar 2009, 17:20
von Trundle
@str1442: Iterator-Objekte sollten auch eine `__iter__`-Methode haben, die einfach das Objekt selbst wieder zurückgibt, damit man auch über das Iterator-Objekt iterieren kann.