2016-08-02 6 views
0

У меня есть класс Count, который принимает 3 параметра, включая self, mystart и myend. Он должен рассчитывать от mystart до myend (также наоборот) с использованием магических методов __iter__, __next__ и __reversed__. Я реализовал все три магических метода. Но я все еще не уверен, что это правильный путь для реализации следующих и обратных методов. Возможно ли, что я могу вызывать встроенные функции дальше и наоборот в моих методах __next__ и __reversed__ или есть ли какой-нибудь пифонический путь?__reversed__ Волшебный метод

class Count: 

    def __init__(self,mystart,myend): 
     self.mystart=mystart 
     self.myend=myend 
     self.current=mystart 
     self.reverse=[] 


    def __iter__(self): 
     "Returns itself as an Iterator Object" 
     return self 

    def __next__(self): 
     if self.current > self.myend: 
      raise StopIteration 
     else: 
      self.current+=1 
      return self.current-1 

    def __reversed__(self): 
     for i in range(self.myend,self.mystart,-1): 
      self.reverse.append(i) 
     return self.reverse 


obj1=Count(0,10) 
print("FOR LOOP") 
for i in obj1: 
    print (i,end=",") 

print ("\nNEXT") 
obj2=Count(1,4) 
print(next(obj2)) 
print(next(obj2)) 

print ("Reversed") 
print(reversed(obj1)) 
+0

нам для того, чтобы знать, что «правильный» путь, каков желаемый результат. Ваш код не выглядит так плохо – wheaties

+0

Но я создаю новый список в моем методе __reversed__, который не дает мне хорошего чувства. :) –

+1

Не имеет смысла давать итератору метод '__reversed__'. Это для последовательностей и других многозадачных итераций с порядковым представлением. – user2357112

ответ

1

Теперь я сделал это, используя инструкцию yield. @jedwards спасибо за ваш типп.

class Count: 

    def __init__(self, mystart,myend): 
     self.mystart = mystart 
     self.myend = myend 
     self.current=None 

    def __iter__(self): 
     self.current = self.mystart 
     while self.current < self.myend: 
      yield self.current 
      self.current += 1 

    def __next__(self): 
     if self.current is None: 
      self.current=self.mystart     
     if self.current > self.myend: 
      raise StopIteration 
     else: 
      self.current+=1 
      return self.current-1 

    def __reversed__(self): 
     self.current = self.myend 
     while self.current >= self.mystart: 
      yield self.current 
      self.current -= 1 

obj1=Count(0,10)  
for i in obj1: 
    print (i) 

obj2=reversed(obj1) 
for i in obj2: 
    print (i) 

obj3=Count(0,10) 
print (next(obj3)) 
print (next(obj3)) 
print (next(obj3)) 
+1

Примечание: ваш метод '__next__' бесполезен, потому что при повторении итерации python будет вызываться' __next__' * генератора *, возвращенного по '__iter__' (добавьте' print' и проверьте, что он никогда не вызывается). этот «текущий» теперь является только локальной переменной * для '__iter__' и' __reversed__', поэтому вы должны просто использовать 'current' вместо' self.current' и удалить 'self.current = None' из' __init__ '. – Bakuriu

+0

Да, вы правы. –

1

Вы путаете итераторы и итерируемые:

итераторы:

  1. Сохраняйте состояние, связанное с их текущим прогрессом итерации
  2. Реализовать __next__, чтобы получить следующее состояние
  3. Реализовать __iter__, чтобы возвратиться.

итерируемые:

  1. Содержит (или определить с каким-то правилом) совокупность элементов, которые могут быть пройдены
  2. Реализовать __iter__ вернуть итератор, который может пересекать элементы
  3. может реализовать __reversed__ для возврата итератора, который возвращается назад.

The __reversed__ magic method is:

Вызывается (если они присутствуют) путем обратный() встроенный для реализации обратного итерации. Он должен вернуть новый объект итератора, который выполняет итерации по всем объектам в контейнере в обратном порядке.

Таким образом, вы, вероятно, не хотите реализовать итератор, который может быть __reversed__ середине итерации, например, реализация in your answer означает, что этот код:

x = Count(1,10) 
for i in x: 
    for j in x: 
     print(i,j) 

вызовет бесконечный цикл, выход просто повторил этот образец:

причина этого заключается в том, потому что оба for петли меняются self.current в противоположном направлении s, внешний цикл будет увеличивать его на 1, тогда внутренний цикл установит его на self.myend и опустит его на 0, затем процесс повторится.

Единственный способ правильно выполнить все три магические методы, чтобы использовать два класса, один для итератора и один за итерацию:

class _Count_iter: 
    def __init__(self, start, stop, step=1): 
     self.current = start 
     self.step = step 
     self.myend = stop 

    def __iter__(self):return self 

    def __next__(self): 
     #if current is one step over the end 
     if self.current == self.myend+self.step: 
      raise StopIteration 
     else: 
      self.current+=self.step 
      return self.current-self.step 


class Count: 

    def __init__(self, mystart,myend): 
     self.mystart = mystart 
     self.myend = myend 

    def __iter__(self): 
     return _Count_iter(self.mystart,self.myend,1) 
    def __reversed__(self): 
     return _Count_iter(self.myend, self.mystart, -1) 
Смежные вопросы