Тут придется имитировать рекурсию через стек состояний (аналог стека вызовов при рекурсии). При входе внутрь вложенного списка кладем текущее состояние в стек (внешний список и положение в нем), при завершении обхода вложенного списка вытаскиваем предыдущее состояние из стека.
class FlatIterator:
def __init__(self, list_of_list):
self.stack = []
self.current_list = list_of_list
self.counter = 0
def __iter__(self):
return self
def __next__(self):
if self.counter >= len(self.current_list):
if self.stack:
# Дошли до конца вложенного списка,
# выходим из него во внешний, "вспоминаем" состояние
self.current_list, self.counter = self.stack.pop()
return next(self)
else:
raise StopIteration
item = self.current_list[self.counter]
self.counter += 1
if type(item) is not list:
return item
else:
# Запоминаем текущее состояние
self.stack.append((self.current_list, self.counter))
# Входим во вложенный список, он становится текущим списком
self.current_list = item
self.counter = 0
return next(self)
list_of_lists_2 = [
[['a'], ['b', 'c']],
['d', 'e', [['f'], 'h'], False],
[1, 2, None, [[[[['!']]]]], []],
]
print(list(FlatIterator(list_of_lists_2)))
Вывод:
['a', 'b', 'c', 'd', 'e', 'f', 'h', False, 1, 2, None, '!']
В общем, то еще "удовольствие", через рекурсивную функцию-генератор получается намного проще.
Можно внутри класса использовать итераторы вместо списков, тогда не нужно будет хранить индекс в списке:
class FlatIterator:
def __init__(self, list_of_list):
self.stack = []
self.current_iterator = iter(list_of_list)
def __iter__(self):
return self
def __next__(self):
try:
item = next(self.current_iterator)
except StopIteration:
if self.stack:
# Дошли до конца вложенного списка,
# выходим из него во внешний, "вспоминаем" состояние
self.current_iterator = self.stack.pop()
return next(self)
else:
# Выходить выше некуда, значит дошли до конца внешнего списка,
# просто выбрасываем исключение (StopIteration) заново
raise
if type(item) is not list:
return item
else:
# Запоминаем текущее состояние
self.stack.append(self.current_iterator)
# Входим во вложенный список, он становится текущим списком
self.current_iterator = iter(item)
return next(self)
list_of_lists_2 = [
[['a'], ['b', 'c']],
['d', 'e', [['f'], 'h'], False],
[1, 2, None, [[[[['!']]]]], []],
]
print(list(FlatIterator(list_of_lists_2)))
Также, чтобы код был точно не рекурсивным, нужно избавиться от вызовов next(self)
из метода __next__
(по сути метод вызывает сам себя). Для этого нужно обернуть код в методе в while True
и вызовы next(self)
заменить на continue
:
class FlatIterator:
...
def __next__(self):
while True:
try:
item = next(self.current_iterator)
except StopIteration:
if self.stack:
# Дошли до конца вложенного списка,
# выходим из него во внешний, "вспоминаем" состояние
self.current_iterator = self.stack.pop()
continue
else:
# Выходить выше некуда, значит дошли до конца внешнего списка,
# просто выбрасываем исключение (StopIteration) заново
raise
if type(item) is not list:
return item
else:
# Запоминаем текущее состояние
self.stack.append(self.current_iterator)
# Входим во вложенный список, он становится текущим списком
self.current_iterator = iter(item)
# continue
...