Source code for monad.types.lazysequence

# -*- coding: utf-8 -*-
# Copyright (c) 2012-2014, Philip Xu <pyx@xrefactor.com>
# License: BSD New, see LICENSE for details.
"""monad.types.lazysequence - a sequence type with lazy evaluation."""

from collections import Sequence
from functools import total_ordering
from itertools import islice

from ..utils import suppress


[docs]@total_ordering class LazySequence(Sequence): """Sequence with lazy evaluation. >>> from itertools import count >>> seq = LazySequence(count()) >>> seq[1] 1 >>> list(seq[3:5]) [3, 4] >>> list(seq[:20:2]) [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] """ def __init__(self, iterable): self.iterable = iter(iterable) self.items = [] def __getitem__(self, index): if isinstance(index, slice): iterable = islice(self, index.start, index.stop, index.step) return self.__class__(iterable) if self.iterable is None: # that's all we have return self.items[index] item_numbers = len(self.items) finished = object() # get until enough while index < 0 or index >= item_numbers: next_item = next(self.iterable, finished) if next_item is finished: self.iterable = None break self.items.append(next_item) item_numbers += 1 return self.items[index] def __len__(self): return len(self.strict.items) def __eq__(self, other): if self is other: return True elif isinstance(other, type(self)): return self.strict.items == other.strict.items else: return NotImplemented def __lt__(self, other): if self is other: return False elif isinstance(other, type(self)): return self.strict.items < other.strict.items else: fmt = "unorderable types: {} and {}'".format raise TypeError(fmt(type(self), type(other))) @property def strict(self): """Proxy to self that forces evaluation when accessed.""" if self.iterable is not None: # force consume all items from self.iterable first with suppress(IndexError): id(self[-1]) return self