Создайте базовый итератор Python



Answers

Существует четыре способа создания итеративной функции:

Примеры:

# generator
def uc_gen(text):
    for char in text:
        yield char.upper()

# generator expression
def uc_genexp(text):
    return (char.upper() for char in text)

# iterator protocol
class uc_iter():
    def __init__(self, text):
        self.text = text
        self.index = 0
    def __iter__(self):
        return self
    def __next__(self):
        try:
            result = self.text[self.index].upper()
        except IndexError:
            raise StopIteration
        self.index += 1
        return result

# getitem method
class uc_getitem():
    def __init__(self, text):
        self.text = text
    def __getitem__(self, index):
        result = self.text[index].upper()
        return result

Чтобы увидеть все четыре метода в действии:

for iterator in uc_gen, uc_genexp, uc_iter, uc_getitem:
    for ch in iterator('abcde'):
        print ch,
    print

Результат:

A B C D E
A B C D E
A B C D E
A B C D E

Примечание .

Два типа генератора ( uc_gen и uc_genexp ) не могут быть reversed() ; для простого итератора ( uc_iter ) нужен метод __reversed__ magic (который должен возвращать новый итератор, который идет назад); и итеративный метод getitem ( uc_getitem ) должен иметь метод __len__ magic:

    # for uc_iter
    def __reversed__(self):
        return reversed(self.text)

    # for uc_getitem
    def __len__(self)
        return len(self.text)

Чтобы ответить на второстепенный вопрос полковника Паника о бесконечно лениво оцененном итераторе, вот эти примеры, используя каждый из четырех вышеперечисленных методов:

# 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

Что приводит к (по крайней мере, для моего пробного запуска):

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
Question

Как создать итеративную функцию (или объект-итератор) в python?




Я вижу, что некоторые из вас __iter__ return self в __iter__ . Я просто хотел отметить, что сам __iter__ может быть генератором (таким образом устраняя необходимость в __next__ и повышая исключения StopIteration )

class range:
  def __init__(self,a,b):
    self.a = a
    self.b = b
  def __iter__(self):
    i = self.a
    while i < self.b:
      yield i
      i+=1

Конечно, здесь можно было бы также сделать генератор, но для более сложных классов это может быть полезно.




Это итеративная функция без урона. Он использует iter функцию и закрытие, которое сохраняет его состояние в изменяемом ( list ) в охватывающей области для python 2.

def count(low, high):
    counter = [0]
    def tmp():
        val = low + counter[0]
        if val < high:
            counter[0] += 1
            return val
        return None
    return iter(tmp, None)

Для Python 3 состояние закрытия сохраняется в неизменяемом в охватывающей области, а nonlocal используется в локальной области для обновления переменной состояния.

def count(low, high):
    counter = 0
    def tmp():
        nonlocal counter
        val = low + counter
        if val < high:
            counter += 1
            return val
        return None
    return iter(tmp, None)  

Контрольная работа;

for i in count(1,10):
    print(i)
1
2
3
4
5
6
7
8
9



Related