pyiter.transform
1from abc import ABC, abstractmethod 2from typing import Any, Generic, Iterable, Iterator, List, Optional, TypeVar, Generator 3 4 5T = TypeVar("T") 6 7U = TypeVar("U") 8 9O = TypeVar("O") 10 11K = TypeVar("K") 12 13 14class Transform(ABC, Generic[T, U], Iterable[U]): 15 """A transform that applies a function to an iterable.""" 16 17 iter: Iterable[T] 18 cache: Optional[List[U]] 19 20 def __init__(self, iter: Iterable[T], *args: Any, **kwargs: Any): 21 from .sequence import Sequence 22 23 self.iter = iter.__transform__ if isinstance(iter, Sequence) else iter 24 self.cache = None 25 26 def __iter__(self) -> Iterator[U]: 27 if self.cache: 28 yield from self.cache 29 else: 30 cache: List[U] = [] 31 for x in self.__do_iter__(): 32 cache.append(x) 33 yield x 34 self.cache = cache 35 36 def __len__(self) -> int: 37 # if not isinstance(self.iter, Transform): 38 # # not Sequence, just a wrapper of List, Tuple.etc. 39 # # we can get lenght of it directly. 40 # if hasattr(self.iter, '__len__'): 41 # return len(self.iter) # type: ignore 42 # elif hasattr(self.iter, '__length_hint__'): 43 # return self._iter.__length_hint__() # type: ignore 44 # we need iterate all to get length 45 cache = self.cache 46 if cache is None: 47 for _ in self: 48 pass 49 cache = self.cache 50 if cache is not None: 51 return len(cache) 52 return 0 53 54 def __repr__(self) -> str: 55 return self.__class__.__name__ 56 57 @abstractmethod 58 def __do_iter__(self) -> Iterator[U]: 59 raise NotImplementedError 60 61 def transforms(self) -> "Iterable[Transform[Any, Any]]": 62 inner = self.iter 63 if isinstance(inner, Transform): 64 yield from inner.transforms() 65 yield self 66 67 68class NonTransform(Transform[T, T]): 69 """ 70 A [Transform] that does not transform the values. 71 """ 72 73 def __init__(self, iter: Iterable[T]) -> None: 74 super().__init__(iter) 75 # self.cache = iter if isinstance(iter, list) else [*iter] 76 77 def __repr__(self) -> str: 78 return f"{self.__class__.__name__}[{self.iter.__class__.__name__}]" 79 80 def __do_iter__(self) -> Iterator[T]: 81 yield from self.iter 82 83 def __len__(self) -> int: 84 if not isinstance(self.iter, Transform): 85 # not Sequence, just a wrapper of List, Tuple.etc. 86 # we can get lenght of it directly. 87 if hasattr(self.iter, "__len__"): 88 return len(self.iter) # type: ignore 89 elif hasattr(self.iter, "__length_hint__"): 90 return self.iter.__length_hint__() # type: ignore 91 return super().__len__() 92 93 94class InfinityTransform(Transform[T, T]): 95 """Transform that iterates over an infinite sequence.""" 96 97 __cache__: List[T] 98 99 def __init__(self, iter: Iterable[T]) -> None: 100 super().__init__(iter) 101 self.__cache__ = [] 102 103 def __repr__(self) -> str: 104 return f"{self.__class__.__name__}[{self.iter.__class__.__name__}]" 105 106 def __do_iter__(self) -> Iterator[T]: 107 cache = self.__cache__ 108 yield from cache 109 for x in self.iter: 110 cache.append(x) 111 yield x 112 113 def __len__(self) -> int: 114 if self.cache is not None: 115 return len(self.cache) 116 raise OverflowError("Cannot determine the length of an infinite sequence.") 117 118 119def new_transform(iter: Iterable[T]) -> Transform[Any, T]: 120 from .sequence import Sequence 121 122 if isinstance(iter, Sequence): 123 return iter.__transform__ 124 125 if isinstance(iter, Transform): 126 return iter # type: ignore 127 128 if isinstance(iter, Generator): 129 return InfinityTransform(iter) # type: ignore 130 131 if isinstance(iter, (list, tuple)): 132 return NonTransform(iter) 133 134 return NonTransform(iter)
class
Transform(abc.ABC, typing.Generic[~T, ~U], typing.Iterable[~U]):
15class Transform(ABC, Generic[T, U], Iterable[U]): 16 """A transform that applies a function to an iterable.""" 17 18 iter: Iterable[T] 19 cache: Optional[List[U]] 20 21 def __init__(self, iter: Iterable[T], *args: Any, **kwargs: Any): 22 from .sequence import Sequence 23 24 self.iter = iter.__transform__ if isinstance(iter, Sequence) else iter 25 self.cache = None 26 27 def __iter__(self) -> Iterator[U]: 28 if self.cache: 29 yield from self.cache 30 else: 31 cache: List[U] = [] 32 for x in self.__do_iter__(): 33 cache.append(x) 34 yield x 35 self.cache = cache 36 37 def __len__(self) -> int: 38 # if not isinstance(self.iter, Transform): 39 # # not Sequence, just a wrapper of List, Tuple.etc. 40 # # we can get lenght of it directly. 41 # if hasattr(self.iter, '__len__'): 42 # return len(self.iter) # type: ignore 43 # elif hasattr(self.iter, '__length_hint__'): 44 # return self._iter.__length_hint__() # type: ignore 45 # we need iterate all to get length 46 cache = self.cache 47 if cache is None: 48 for _ in self: 49 pass 50 cache = self.cache 51 if cache is not None: 52 return len(cache) 53 return 0 54 55 def __repr__(self) -> str: 56 return self.__class__.__name__ 57 58 @abstractmethod 59 def __do_iter__(self) -> Iterator[U]: 60 raise NotImplementedError 61 62 def transforms(self) -> "Iterable[Transform[Any, Any]]": 63 inner = self.iter 64 if isinstance(inner, Transform): 65 yield from inner.transforms() 66 yield self
A transform that applies a function to an iterable.
69class NonTransform(Transform[T, T]): 70 """ 71 A [Transform] that does not transform the values. 72 """ 73 74 def __init__(self, iter: Iterable[T]) -> None: 75 super().__init__(iter) 76 # self.cache = iter if isinstance(iter, list) else [*iter] 77 78 def __repr__(self) -> str: 79 return f"{self.__class__.__name__}[{self.iter.__class__.__name__}]" 80 81 def __do_iter__(self) -> Iterator[T]: 82 yield from self.iter 83 84 def __len__(self) -> int: 85 if not isinstance(self.iter, Transform): 86 # not Sequence, just a wrapper of List, Tuple.etc. 87 # we can get lenght of it directly. 88 if hasattr(self.iter, "__len__"): 89 return len(self.iter) # type: ignore 90 elif hasattr(self.iter, "__length_hint__"): 91 return self.iter.__length_hint__() # type: ignore 92 return super().__len__()
A [Transform] that does not transform the values.
Inherited Members
95class InfinityTransform(Transform[T, T]): 96 """Transform that iterates over an infinite sequence.""" 97 98 __cache__: List[T] 99 100 def __init__(self, iter: Iterable[T]) -> None: 101 super().__init__(iter) 102 self.__cache__ = [] 103 104 def __repr__(self) -> str: 105 return f"{self.__class__.__name__}[{self.iter.__class__.__name__}]" 106 107 def __do_iter__(self) -> Iterator[T]: 108 cache = self.__cache__ 109 yield from cache 110 for x in self.iter: 111 cache.append(x) 112 yield x 113 114 def __len__(self) -> int: 115 if self.cache is not None: 116 return len(self.cache) 117 raise OverflowError("Cannot determine the length of an infinite sequence.")
Transform that iterates over an infinite sequence.
Inherited Members
120def new_transform(iter: Iterable[T]) -> Transform[Any, T]: 121 from .sequence import Sequence 122 123 if isinstance(iter, Sequence): 124 return iter.__transform__ 125 126 if isinstance(iter, Transform): 127 return iter # type: ignore 128 129 if isinstance(iter, Generator): 130 return InfinityTransform(iter) # type: ignore 131 132 if isinstance(iter, (list, tuple)): 133 return NonTransform(iter) 134 135 return NonTransform(iter)