Liste wieder und wieder durchlaufen bis die Anzahl der zurückgegebenen Elemente stimmt

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Sirius3
User
Beiträge: 17757
Registriert: Sonntag 21. Oktober 2012, 17:20

Was erwartest Du? Der Generator liefert eine islice-Instanz zurück.
Ein Generator, der genau ein Element liefert ist auch nicht sehr sinnvoll.
Was ist der Sinn dahinter, diesen Generator 10 mal in einer Schleife zu erzeugen?

islice benutzt man wie einen Generator oder jeden anderen Iterator mit einer for-Schleife oder ähnlichem. Ich verstehe nicht, was Du hier noch erreichen willst.
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

Eigentlich wollte ich bei jedem Aufruf des Generators ein weiteres Element nach der vorbestimmten Reihenfolge aus der Liste `numbers[]` zurückbekommen.

Gruß
Atalanttore
Benutzeravatar
__blackjack__
User
Beiträge: 13119
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Atalanttore: Und das bekommst Du nicht? Und mal so nebenbei ist die Frage ob das ein Generator ist dafür ziemlich irrelevant weil hier im ganzen Thema bis her nur die Eigenschaften eines iterierbaren Objekts genutzt werden.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Sirius3
User
Beiträge: 17757
Registriert: Sonntag 21. Oktober 2012, 17:20

Jedesmal, wenn Du eine Generatorfunktion aufrufst, erhältst Du einen neuen Generator, von dem Du per next immer das einzige Element abfragst und das ist eben die islice-Instanz, so wie Du es programmiert hast.
Aber Du hast Dich da mit dem Generator verrannt, den brauchst Du nicht.

Code: Alles auswählen

from itertools import islice, cycle

numbers = [1,2,3,4,5,6,7,8,9,10]

def liste(l):
    return islice(cycle(l), 25)

for i in range(liste(numbers)):
    print(i)
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

__blackjack__ hat geschrieben: Samstag 11. August 2018, 20:48 @Atalanttore: Und das bekommst Du nicht? Und mal so nebenbei ist die Frage ob das ein Generator ist dafür ziemlich irrelevant weil hier im ganzen Thema bis her nur die Eigenschaften eines iterierbaren Objekts genutzt werden.
Im folgenden Beispiel wird auf die Anweisung, ob das Objekt ein `GeneratorType` ist, ein `True` zurückgegeben.

Code: Alles auswählen

numbers = []

for i in range(65):
    numbers.append(i)

def liste(l):
    number = islice(cycle(l), 120000)
    yield number

print(isinstance(liste(numbers), types.GeneratorType))

Sirius3 hat geschrieben: Samstag 11. August 2018, 20:55

Code: Alles auswählen

from itertools import islice, cycle

numbers = [1,2,3,4,5,6,7,8,9,10]

def liste(l):
    return islice(cycle(l), 25)

for i in range(liste(numbers)):
    print(i)
Darauf erscheint bei mir leider diese Fehlermeldung:

Code: Alles auswählen

Traceback (most recent call last):
  File "/home/ata/source/test2.py", line 8, in <module>
    for i in range(liste(numbers)):
TypeError: 'itertools.islice' object cannot be interpreted as an integer
Gruß
Atalanttore
Sirius3
User
Beiträge: 17757
Registriert: Sonntag 21. Oktober 2012, 17:20

War ja auch falsch:

Code: Alles auswählen

for i in liste(numbers):
    print(i)
Benutzeravatar
__blackjack__
User
Beiträge: 13119
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Atalanttore: Das ist ja schön das da True bei raus kommt und das ist ja auch richtig, aber das ändert nichts an meiner Bemerkung das die speziellen Eigenschaften eines Generators hier nirgends verwendet und damit auch nicht gebraucht werden. Hier wird nur iteriert und weder `send()`, `close()`, noch `throw()` aufgerufen. Solange man das nicht macht/braucht ist es Wurst ob man einen Generator oder ”nur” einen Iterator hat. Solange nicht `next()` selbst aufgerufen wird, sondern das ganze in einer ``for``-Schleife verarbeitet wird, braucht man nicht einmal einen Iterator, es reicht, dass das Objekt iterierbar ist, man also mit `iter()` einen Iterator von dem Objekt bekommen kann.

Dein Beispiel macht auch keinen Sinn.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

Sirius3 hat geschrieben: Samstag 11. August 2018, 21:09 War ja auch falsch:

Code: Alles auswählen

for i in liste(numbers):
    print(i)
Damit funktioniert es:

Code: Alles auswählen

from itertools import islice, cycle

numbers = [1,2,3,4,5,6,7,8,9,10]

def liste(l):
    return islice(cycle(l), 25)

for i in liste(numbers):
    print(i)
Wird in der for-Schleife mit der Funktion `liste()` bei jeder Iteration der passende Rückgabewert zum Index `i` neu berechnet?

__blackjack__ hat geschrieben: Samstag 11. August 2018, 21:14 @Atalanttore: Das ist ja schön das da True bei raus kommt und das ist ja auch richtig, aber das ändert nichts an meiner Bemerkung das die speziellen Eigenschaften eines Generators hier nirgends verwendet und damit auch nicht gebraucht werden. Hier wird nur iteriert und weder `send()`, `close()`, noch `throw()` aufgerufen. Solange man das nicht macht/braucht ist es Wurst ob man einen Generator oder ”nur” einen Iterator hat.
`send()` und `throw()` habe ich noch nie benutzt/gebraucht und `close()` nur für das Schließen eines Dateiobjekts.

__blackjack__ hat geschrieben: Samstag 11. August 2018, 21:14 Solange nicht `next()` selbst aufgerufen wird, sondern das ganze in einer ``for``-Schleife verarbeitet wird, braucht man nicht einmal einen Iterator, es reicht, dass das Objekt iterierbar ist, man also mit `iter()` einen Iterator von dem Objekt bekommen kann.
Also mit `iter()` kann man einen Iterator (Zeiger?) vom Objekt (Liste?) erstellen. Bei jedem Zugriff mit `next()` auf diesen Iterator wird automatisch das Element, das auf das zuletzt zurückgegebene Element im Iterator folgt, zurückgegeben. Habe ich das so richtig verstanden?

Gruß
Atalanttore
Benutzeravatar
__blackjack__
User
Beiträge: 13119
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Atalanttore: Ob `cycle()` mit Indexwerten arbeitet, also Sequenztypen gesondert behandelt, wäre ein Implementierungsdetail. Das muss ja mit beliebigen iterierbaren Objekten funktionieren und nicht nur mit Sequenztypen wie Listen. Eine allgemeine Implementierung wäre also in zwei Phasen — in der ersten Phase werden die Elemente des Arguments zum Beispiel in einer Liste gespeichert *und* durchgereicht, und in der zweiten Phase wird entweder immer wieder über diese Liste iteriert. Ob nun mit Index oder über Iterator kann ja eigentlich egal sein. Wer's wissen möchte schaut halt in den Quelltext.

Ich wäre vorsichtig damit einen Iterator als Zeiger zu bezeichnen. Das Wort hat ja eine spezielle Bedeutung in der Programmierung und in dem Sinne ist ein Iterator kein Zeiger. Ein Iterator implementiert `__iter__()` — in der Regel liefert das Objekt dabei sich selbst zurück, und `__next__()` (Python 3) oder `next()` (Python 2). Letztere Methode liefert das nächste Element, oder löst eine `StopIteration` aus wenn es kein nächstes Element mehr gibt.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

Ich habe das bestehende Beispiel auf die Verwendung eines Iterators umgebaut.

Code: Alles auswählen

from itertools import islice, cycle

numbers = []
for i in range(10):
    numbers.append(i)

iterator = iter(islice(cycle(numbers), 25))

for i in range(26):
    print(next(iterator))
Allerdings haben die Anweisungen `__iter__()` und `__next__()` bei mir (Python 3.6) nicht funktioniert und ich musste die Unterstriche weglassen.

Gruß
Atalanttore
Benutzeravatar
__blackjack__
User
Beiträge: 13119
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Atalanttore: Das macht keinen Sinn, warum machst Du das so umständlich? Jetzt hast Du einen zweiten Iterator und ein `i` das Du überhaupt nicht verwendest. Die erste Schleife ist auch unnötig kompliziert. Der Code sollte so aussehen:

Code: Alles auswählen

from itertools import islice, cycle

numbers = list(range(10))
for number in islice(cycle(numbers), 25):
    print(number)
`__iter__()` und `__next__()` sind die Methoden die das iterierbare Objekt und der Iterator haben müssen damit die Funktionen `iter()` und `next()` damit funktionieren. Also das iterierbare Objekt muss `__iter__()` implementieren und der Iterator beides.

(Das stimmt nicht so ganz, weil es noch andere Möglichkeiten gibt ein Objekt iterierbar zu machen, das hat aber eher historischen Wert.)
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
narpfel
User
Beiträge: 645
Registriert: Freitag 20. Oktober 2017, 16:10

Man muss noch nichtmal das `range`-Objekt in eine Liste umwandeln:

Code: Alles auswählen

from itertools import islice, cycle

for number in islice(cycle(range(10)), 25):
    print(number)
Benutzeravatar
__blackjack__
User
Beiträge: 13119
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Stimmt. :-)
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Sirius3
User
Beiträge: 17757
Registriert: Sonntag 21. Oktober 2012, 17:20

Dass islice schon ein Iterator ist, läßt sich leicht zeigen, indem man schaut, ob `iter` das selbe Element liefert

Code: Alles auswählen

from itertools import islice, cycle

iterator = islice(cycle(range(10)), 25)
print(iterator is iter(iterator))
# > True
Antworten