Создайте базовый итератор Python
Есть четыре способа создать python итеративную функцию:
- создать генератор (использует yield keyword)
- использовать выражение генератора (genexp)
- создать итератор (определяет
__iter__
and__next__
(илиnext
в Python 2.x)) - создать класс, который Python может перебирать самостоятельно (defines
__getitem__
)
Примеры:
# generator
def uc_gen(text):
for char in text.upper():
yield char
# generator expression
def uc_genexp(text):
return (char for char in text.upper())
# iterator protocol
class uc_iter():
def __init__(self, text):
self.text = text.upper()
self.index = 0
def __iter__(self):
return self
def __next__(self):
try:
result = self.text[self.index]
except IndexError:
raise StopIteration
self.index += 1
return result
# getitem method
class uc_getitem():
def __init__(self, text):
self.text = text.upper()
def __getitem__(self, index):
return self.text[index]
Чтобы object увидеть все четыре метода object в действии:
for iterator in uc_gen, uc_genexp, uc_iter, uc_getitem:
for ch in iterator('abcde'):
print(ch, end=' ')
print()
В результате:
A B C D E
A B C D E
A B C D E
A B C D E
Примечание:
Два listiterator типа генераторов (uc_gen
и uc_genexp
) не object могут быть reversed()
; простому итератору pythonic (uc_iter
) потребуется магический pythonista метод __reversed__
(который, according to the docs, должен iterator возвращать новый итератор, но python возврат self
работает (по крайней iterators мере, в CPython)); и итерация listiterator getitem (uc_getitem
) должна иметь магический python-interpreter метод __len__
:
# for uc_iter we add __reversed__ and update __next__
def __reversed__(self):
self.index = -1
return self
def __next__(self):
try:
result = self.text[self.index]
except IndexError:
raise StopIteration
self.index += -1 if self.index < 0 else +1
return result
# for uc_getitem
def __len__(self)
return len(self.text)
Чтобы ответить на py вторичный вопрос полковника python-interpreter Паника о бесконечном лениво pythonic вычисляемом итераторе, вот python-interpreter эти примеры с использованием listiterator каждого из четырех методов, описанных py выше:
# generator
def even_gen():
result = 0
while True:
yield result
result += 2
# generator expression
def even_genexp():
return (num for num in even_gen()) # or even_iter or even_getitem
# not much value under these circumstances
# iterator protocol
class even_iter():
def __init__(self):
self.value = 0
def __iter__(self):
return self
def __next__(self):
next_value = self.value
self.value += 2
return next_value
# getitem method
class even_getitem():
def __getitem__(self, index):
return index * 2
import random
for iterator in even_gen, even_genexp, even_iter, even_getitem:
limit = random.randint(15, 30)
count = 0
for even in iterator():
print even,
count += 1
if count >= limit:
break
print
В результате (по крайней iterators мере, для моего пробного iterators запуска):
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32
Как выбрать, какой py использовать? Это в основном pythonic дело вкуса. Чаще всего я python-interpreter вижу два метода: генераторы listiterator и протокол итератора, а также python-shell гибрид (__iter__
возвращает генератор).
Выражения object генератора полезны для замены python понимания списков (они ленивы python-shell и поэтому могут экономить pythonic ресурсы).
Если вам нужна совместимость objects с более ранними версиями pythonic Python 2.x, используйте __getitem__
.
python
object
iterator
Создайте базовый итератор Python
Мы используем файлы cookies для улучшения работы сайта. Оставаясь на нашем сайте, вы соглашаетесь с условиями использования файлов cookies. Чтобы ознакомиться с нашими Положениями о конфиденциальности и об использовании файлов cookie, нажмите здесь.