дан генератор
g = ( <expr> for x in <iter> ),
есть ли способ восстановить выражение и итератор, использованный для определения g?
Например, функция, которая будет вести себя так:
expr, iter = f( ( x*x for x in range(10) ) )
expr(2) # 4
expr(5) # 25
iter[1] # 1
iter[9] # 9
iter[10] # raises IndexError
Причина, по которой я хочу эту функциональность, заключается в том, что я создал свой собственный класс LazyList. Я хочу, чтобы он по существу вел себя как генератор, за исключением разрешения доступа через getitem без необходимости перебирать элементы k-1, прежде чем он сможет получить доступ к k-му элементу. Спасибо.
Редактировать: Вот снимок класса ленивого списка:
class LazyList(object):
def __init__(self, iter=None, expr=None):
if expr is None:
expr = lambda i: i
if iter is None:
iter = []
self._expr = expr
self._iter = iter
def __getitem__(self, key):
if hasattr(self._iter, '__getitem__'):
return self._expr(self._iter[key])
else:
return self._iter_getitem(key)
def __iter__(self):
for i in self._iter:
yield self._expr(i)
Я опустил метод _iter_getitem. Все, что он делает, это перебирает _iter, пока не достигнет ключевого элемента (или не использует iserice itertool, если key является слайсом). Есть также общие функции llmap, llreduce и т. Д., Которые я пропустил, но вы, вероятно, можете догадаться, как они идут.
Одна из причин, по которой я хочу разложить генераторы, заключается в том, что я могу элегантно инициализировать этот класс, например
l = LazyList(x*x for x in range(10))
вместо
l = LazyList(range(10), lambda x: x*x)
Но реальное преимущество состоит в том, что это было бы, с полнотой, хорошим обобщением концепции генератора и могло бы использоваться вместо любого генератора (с теми же преимуществами экономии памяти).
Я часто использую это с Django, потому что он хорошо работает с их наборами запросов. У меня есть много кода, который зависит от ленивых структур списков, потому что он возвращает многомерные массивы, которые, если их оценить, извлекут намного больше данных, чем мне нужно.