Trochę nie tędy droga. W języku Python można na kilka sposobów napisać generator:
1. Zwracać z funkcji dane z użyciem yield (będzie wtedy działać domknięcie)
2. Użyć postaci generatorowej i otoczyć ją nawiasami zwykłymi (w wyniku powstanie generator)
3. Użyć wersji obiektowej implementacji generatora (trzeba tworzyć wtedy klasę i zaimplementować odpowiednie metody).
W tym zadaniu masz 2 ścieżki wykonania i to zrobione jest dobrze. W jednej zwracasz proste itertools.cycle(sekwencja) a w drugiej, zip(...) na "opakowanych itertools.cycle(...) sekwencjach".
No to błędny jeszcze kod:
#!/usr/bin/env python3
def cykliczny(sekwencja, *sekwencje):
from itertools import cycle
if not sekwencje:
return cycle(sekwencja)
return zip(cycle(sek) for sek in (sekwencja, *sekwencje))
if __name__ == '__main__':
# Dwa testy, pierwsze 10 elementów...
for k, v in zip(range(10), cykliczny('abcd')):
print(v)
for k, v in zip(range(10), cykliczny('abcd', 'gh', 'qwer')):
print(v)
Pierwsza ścieżka jest już ok. W drugiej niestety zwraca 3 iteratory:
a
b
c
d
a
b
c
d
a
b
(<itertools.cycle object at 0x1095f3798>,)
(<itertools.cycle object at 0x1095f3750>,)
(<itertools.cycle object at 0x1095f37e0>,)
Czyli trzeba przerobić argumenty zip'a tak aby zwracał rozwinięte argumenty. Chodzi o ten kod
cycle(sek) for sek in (sekwencja, *sekwencje)
Wystarczy że opakujesz je nawiasami ( i ) i będzie z tego generator. Ale niestety nie zostanie on rozwinięty dla zip'a. Wystarczy dodać * (gwiazdkę), co spowoduje rozwinięcie argumentów:
zip(*(cycle(sek) for sek in (sekwencja, *sekwencje)))
Sprawdź jak to działa :)
Jak zauważysz w kodzie, zwracasz albo cykl z 1 sekwencji, albo "zzipowane cykle z pierwszej i dalszych sekwencji". Do takich wyrażeń jest w języku użycie "if po" :)
#!/usr/bin/env python3
def cykliczny(sekwencja, *sekwencje):
from itertools import cycle
return cycle(sekwencja) if not sekwencje else zip(*(cycle(sek) for sek in (sekwencja, *sekwencje)))
if __name__ == '__main__':
# Dwa testy...
for k, v in zip(range(10), cykliczny('abcd')):
print(v)
for k, v in zip(range(10), cykliczny('abcd', 'gh', 'qwer')):
print(v)
Teraz tylko wystarczy zauważyć że tak naprawdę wystarczy w implementacji jedna ścieżka wykonania. To skończy implementację:
#!/usr/bin/env python3
def cykliczny(*args):
from itertools import cycle
return zip(*(cycle(sek) for sek in args))
if __name__ == '__main__':
# Dwa testy...
for k, v in zip(range(10), cykliczny('abcd')):
print(v)
for k, v in zip(range(10), cykliczny('abcd', 'gh', 'qwer')):
print(v)