используя __iter__ и __next__ для создания моего собственного класса - PullRequest
2 голосов
/ 09 июля 2020

Я пытаюсь создать свой собственный класс для итератора и нашел такой пример:

class OddNum:
  """Class to implement iterator protocol"""

  def __init__(self, num = 0):
    self.num = num

  def __iter__(self):
    self.x = 1
    return self

  def __next__(self):
    if self.x <= self.num:
      odd_num = self.x
      self.x += 2
      return odd_num
    else:
      raise StopIteration

for num in OddNum(10):
  print(num)

результат: 1 3 5 7 9

Теперь, если я удалю строку odd_num = self.x и измените return odd_num на return self.x, я получаю следующий результат: 3 5 7 9 11

В чем разница между двумя кодами, почему я должен определять переменную как self.x?

1 Ответ

2 голосов
/ 09 июля 2020

В этом конкретном случае c происходит то, что вы хотите вернуть значение self.x откуда-то из середины метода __next__, прежде чем увеличивать значение self.x, готовое для следующая итерация. Поэтому переменная odd_num используется для хранения этого значения. Если вместо этого вы вернете self.x после оператора self.x += 2 (т.е. прибавите 2), то вы получите другой ответ, как вы видели.

Другой вариант, который вы можете рассмотреть, - это вместо того, чтобы писать свой собственный класс, чтобы реализовать итератор с помощью функции генератора, если вы хотите использовать значение некоторой переменной из середины кода. Это потому, что вы можете поместить оператор yield где угодно. В этом примере это будет выглядеть примерно так:

def odd_num(num=0):
    x = 1
    while x <= num:
        yield x
        x += 2
  
    
for num in odd_num(10):
    print(num)

Это дает:

1
3
5
7
9

(обратите внимание на while вместо if, которое у вас было в ваш метод __next__.)

Здесь оператор yield находится перед оператором x += 2, что не может быть выполнено с помощью return из метода (функции). Поэтому нет необходимости сохранять значение в другой переменной, чтобы использовать его позже.

...