Python: продвижение __iter__ поведение

#python #iterator

#python #итератор

Вопрос:

У меня есть класс словаря с ограниченным размером, и я хочу, чтобы метод iter работал следующим образом:

если значение не равно None, то сгенерируйте. В противном случае пропустите его. Вы знаете, как это реализовать, ребята?

 class myclass(object):
    def __init__(self):
        self.data = {1:'a', 2:None, 3:'c'}

    def __iter__(self):
        return iter(self.data.values())

    def __next__(self): ## <== I THINK THIS IS A WRONG EXAMPLE
        if iter(self): ## BUT I DON"T KNOW HOW TO FIX IT
            return iter(self)

mc = myclass()
for i in mc:
    print(i)
  

Ответ №1:

Если ваш __iter__ метод напрямую возвращает итератор, вам не нужно внедрять __next__ ; в этом случае с ним не будут обращаться (вместо этого используется __next__ метод возвращаемого итератора).

Возвращает выражение генератора:

 class myclass(object):
    def __init__(self):
        self.data = {1:'a', 2:None, 3:'c'}

    def __iter__(self):
        return (v for v in self.data.values() if v is not None)
  

ДЕМОНСТРАЦИЯ:

 >>> class myclass(object):
...     def __init__(self):
...         self.data = {1:'a', 2:None, 3:'c'}
...     def __iter__(self):
...         return (v for v in self.data.values() if v is not None)
... 
>>> list(myclass())
['a', 'c']
  

Вам пришлось бы возвращаться self из __iter__ , если бы вы хотели, чтобы класс был его собственным итератором; это означало бы, что вам нужно было бы отслеживать состояние между __next__ вызовами, чтобы знать, какое значение возвращать из каждого вызова. Для вашего варианта использования вы, скорее всего, не хотите этого.

Ответ №2:

Для создания одноразового итератора:

 class myclass(object):
    def __init__(self):
        self.data = {1:'a', 2:None, 3:'c'}
        self.keys = self.data.keys()
        self.index = 0
    def __iter__(self):
        return self
    def __next__(self):
        index = self.index
        while 'searching for value':
            if index >= len(self.keys):
                raise StopIteration
            key = self.keys[index]
            value = self.data[key]
            index  = 1
            if value is not None:
                self.index = index
                return value
  

Как вы можете видеть, использовать ответ Мартджина намного приятнее.