#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
Как вы можете видеть, использовать ответ Мартджина намного приятнее.