Seite 1 von 1
Generatoren & Iteratoren
Verfasst: Dienstag 18. August 2009, 09:02
von maxwell
Hallo Freunde,
da ich noch relativ neu auf Python-Gebiet bin habe ich folgende Frage.
Ich habe eine eigene Linkliste entworfen und ich stehe nun vor der Problematik, wie ich am geschicktesten die Iteratoren unterbringe. Da wäre zum einen die __iter__() Methode die ich in die Klasse integriere. Das funzt ganz gut nur mit der Einschränkung, dass ich nur GoF iterieren kann. Gibt es hier eine Möglichkeit das anders zu gestallten? z.B. rückwärts iterieren?
Als alternative habe ich ein seperates Modul mit einer vielzahl - so wie ich mir das auch ohnehin vorgestellt habe - an Funktionen.
forwärts/rückwärts iterieren
mit/ohne prefetch
usw.
Was ist jetzt nun am elegantesten?
Viele Grüße,
Chris
Verfasst: Dienstag 18. August 2009, 09:10
von Defnull
Zu wenig Input.
Woher kommen die Links? SQL?
Wie hast du __iter__ implementiert?
Verfasst: Dienstag 18. August 2009, 09:21
von maxwell
hallo Defnull,
Woher kommen die Links? SQL?
welche links?? SQL ???
ich meine verkettete Listen...
n1 n2 n3
p <- p <- p
n -> n -> n
Wie hast du __iter__ implementiert
Code: Alles auswählen
def __iter__(self):
self.current = self.head
return self
def next(self):
if self.current == None:
raise StopIter....
else:
self.current = self.current.next
return self.current
vg chris
Verfasst: Dienstag 18. August 2009, 09:38
von b.esser-wisser
Benutz' doch ein extra Iterator-objekt:
Code: Alles auswählen
class Iterator(object):
def __init__(self, node, forward=True):
self.current = node
self.forward=True
def next(self):
if self.forward:
#...
class LinkedList(...):
def __iter__(self):
return Iterator(self.head)
# rückwärts & extras brauchen zus. Methoden
#oder gehören in abgeleitete Klassen
hth, Jörg
Verfasst: Dienstag 18. August 2009, 09:48
von maxwell
@ b.esser-wisser
ja so hab ich es ja vor. nur wollte ich die syntax beim aufruf von
schön einfach halten. einfach rückwärts iterieren geht hier nicht.
dachte da an
muss doch irgendwie möglich sein an die __iter__ methode ein arg zu übergeben, das dann den richtigen iterator ansteuert.
momentan habe ich es mit generatoren gelöst.
Code: Alles auswählen
def list_for_each(list, item = None):
''' list_for_each() - iterate over a list '''
head = list.head
item = (item.next if item != None else list.head.next)
while item != head:
yield item
item = item.next
def list_for_each_prev(list, item = None):
''' '''
head = list.head
item = (item.prev if item != None else list.head.prev)
while item != head:
yield item
item = item.prev
nur ists hier immer blöd aus dem modulnamensraum heraus die methode aufzurufen. sprich mit
und dann mit
Code: Alles auswählen
for n in iterators.list_for_each(meineZuDurchlaufendeListe):
pass # do anything
anzustoßen.
Ich dachte das kann man irgendwie einfach mit:
machen[/code]
Verfasst: Dienstag 18. August 2009, 09:58
von b.esser-wisser
Code: Alles auswählen
for n in iterators.list_for_each(meineZuDurchlaufendeListe):
pass # do anything
Nein, ich dachte da an eine
Methode:
Code: Alles auswählen
for n in meine_zu_durchlaufende_liste.backwards():
pass

hth, Jörg
ps.:
llist[::1] geht über __getitem__, __setitem__ und sog. slice-Objekte, ist aber wohl erstmal nichtso wichtig
Verfasst: Dienstag 18. August 2009, 12:58
von BlackJack
@maxwell: Gehört Deine `__iter__`-Methode zur `next()`-Methode? Dann ist sie ungewöhnlich, weil ein `iter()` angewendet auf einen Iterator eben jenen Iterator *unverändert* zurückgeben sollte, und nicht wieder von vorne anfangen sollte.
Ansonsten würde ich das wie folgt lösen:
Code: Alles auswählen
class LinkedList(object):
def __iter__(self):
item = self.head
while item is not None:
yield item
item = item.next
def __reversed__(self):
item = self.last
while item is not None:
yield item
item = item.previous
Das `__reversed__()` von der `reversed()`-Funktion aufgerufen wird ist zwar AFAIK nicht dokumentiert, scheint aber bei CPython immer der Fall zu sein.
Verfasst: Dienstag 18. August 2009, 13:03
von Dauerbaustelle
Warum willst du überhaupt einen Iterator für eine Liste implementieren? Die ist doch schon iterierbar. Und für Rückwärts-Iterieren gibts den `reverse`-Iterator.
Gruß
Verfasst: Dienstag 18. August 2009, 13:23
von lunar
Verfasst: Dienstag 18. August 2009, 13:40
von BlackJack
@lunar: Jaaa, in der Doku für 2.6. Wer benutzt denn schon so etwas Neumodisches!?

Bei 2.5 ist das noch nicht dokumentiert, funktioniert aber trotzdem. Zumindest bei CPython.
Verfasst: Dienstag 18. August 2009, 13:47
von lunar
@BlackJack: Man muss eben mit der Zeit gehen

Verfasst: Dienstag 18. August 2009, 13:54
von maxwell
@all
just in time nach einer argen Google-Orgie bin ich auf
__reversed__() gestoßen. wollte gerade noch mal schauen ob noch jemand geantwortet hat und zack... klasse sache.
aber leider habe ich immer noch bauchschmerzen. das gefällt mir alles noch nicht so ganz.
__reversed__() nimmt keine args an.
ich möchte jedoch gerne auch einen startknoten angeben können.
bsp.
ich denke das geht dann nur über slices...
vielen dank euch alle!
vg chris
Verfasst: Dienstag 18. August 2009, 14:10
von EyDu
maxwell hat geschrieben:ch möchte jedoch gerne auch einen startknoten angeben können.
bsp.
Wenn myList ein Exemplar einer eigenen Klasse ist, dann gib der Klasse doch eine Methode die einen solchen Generator erzeugt:
Sonst schreibst du eine Generatorfunktion, welche myList und den Startwert als Parameter bekommt:
Verfasst: Dienstag 18. August 2009, 14:17
von maxwell
@EyDu
so hab ichs momentan auch gemacht.
Code: Alles auswählen
def __iter__(self, i):
''' __iter__() - called if you iterate over list items with
"for" syntax '''
return self.forward()
def __reversed__(self):
''' '''
return self.backward()
def forward(self, item = None):
''' forward() - iterate over a list
@item: an entry from which we will start '''
head = self.head
item = (item.next if item != None else head.next)
while item != head:
yield item
item = item.next
def backward(self, item = None):
''' backward() - iterate over a list backwards '''
head = self.head
item = (item.prev if item != None else head.prev)
while item != head:
yield item
item = item.prev
ich hätte es nur gerne beispielsweise über diesen
ausdruck geschafft:
Verfasst: Dienstag 18. August 2009, 14:45
von EyDu
Dazu könntest du
__getitem__ überschreiben. Das macht aber nur wirklich Sinn, wenn es echte Sequenzen sind, auf deren Elemente per Index zugegriffen werden kann. Alles andere wäre etwas verwirrend.