Skip to content

Commit fa1098a

Browse files
committed
refactor L to pull out methods into separate cells
1 parent 071cf0b commit fa1098a

4 files changed

Lines changed: 1063 additions & 980 deletions

File tree

fastcore/foundation.py

Lines changed: 186 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,9 @@ def __init__(self, items=None, *rest, use_list=False, match=None):
117117
def _xtra(self): return None
118118
def _new(self, items, *args, **kwargs): return type(self)(items, *args, use_list=None, **kwargs)
119119
def __getitem__(self, idx):
120+
"Retrieve `idx` (can be list of indices, or mask, or int) items"
120121
if isinstance(idx,int) and not hasattr(self.items,'iloc'): return self.items[idx]
121122
return self._get(idx) if is_indexer(idx) else L(self._get(idx), use_list=None)
122-
def copy(self): return self._new(self.items.copy())
123123

124124
def _get(self, i):
125125
if is_indexer(i) or isinstance(i,slice): return getattr(self.items,'iloc',self.items)[i]
@@ -143,7 +143,6 @@ def __eq__(self,b):
143143
if isinstance(b, (str,dict)) or callable(b): return False
144144
return all_equal(b,self)
145145

146-
def sorted(self, key=None, reverse=False, cmp=None, **kwargs): return self._new(sorted_ex(self, key=key, reverse=reverse, cmp=cmp, **kwargs))
147146
def __iter__(self): return iter(self.items.itertuples() if hasattr(self.items,'iloc') else self.items)
148147
def __contains__(self,b): return b in self.items
149148
def __reversed__(self): return self._new(reversed(self.items))
@@ -158,88 +157,6 @@ def __addi__(a,b):
158157
a.items += list(b)
159158
return a
160159

161-
@classmethod
162-
def split(cls, s, sep=None, maxsplit=-1): return cls(s.split(sep,maxsplit))
163-
@classmethod
164-
def splitlines(cls, s, keepends=False): return cls(s.splitlines(keepends))
165-
@classmethod
166-
def range(cls, a, b=None, step=None): return cls(range_of(a, b=b, step=step))
167-
168-
def map(self, f, *args, **kwargs): return self._new(map_ex(self, f, *args, gen=False, **kwargs))
169-
def argwhere(self, f, negate=False, **kwargs): return self._new(argwhere(self, f, negate, **kwargs))
170-
def argfirst(self, f, negate=False):
171-
if negate: f = not_(f)
172-
return first(i for i,o in self.enumerate() if f(o))
173-
def filter(self, f=noop, negate=False, **kwargs):
174-
return self._new(filter_ex(self, f=f, negate=negate, gen=False, **kwargs))
175-
176-
def enumerate(self): return L(enumerate(self))
177-
def renumerate(self): return L(renumerate(self))
178-
def unique(self, sort=False, bidir=False, start=None): return L(uniqueify(self, sort=sort, bidir=bidir, start=start))
179-
def val2idx(self): return val2idx(self)
180-
def cycle(self): return cycle(self)
181-
def groupby(self, key, val=noop): return groupby(self, key, val=val)
182-
def map_dict(self, f=noop, *args, **kwargs): return {k:f(k, *args,**kwargs) for k in self}
183-
def map_first(self, f=noop, g=noop, *args, **kwargs):
184-
return first(self.map(f, *args, **kwargs), g)
185-
186-
def itemgot(self, *idxs):
187-
x = self
188-
for idx in idxs: x = x.map(itemgetter(idx))
189-
return x
190-
def attrgot(self, k, default=None):
191-
return self.map(lambda o: o.get(k,default) if isinstance(o, dict) else nested_attr(o,k,default))
192-
193-
def starmap(self, f, *args, **kwargs): return self._new(itertools.starmap(partial(f,*args,**kwargs), self))
194-
def zip(self, cycled=False): return self._new((zip_cycle if cycled else zip)(*self))
195-
def zipwith(self, *rest, cycled=False): return self._new([self, *rest]).zip(cycled=cycled)
196-
def map_zip(self, f, *args, cycled=False, **kwargs): return self.zip(cycled=cycled).starmap(f, *args, **kwargs)
197-
def map_zipwith(self, f, *rest, cycled=False, **kwargs): return self.zipwith(*rest, cycled=cycled).starmap(f, **kwargs)
198-
def shuffle(self):
199-
it = copy(self.items)
200-
random.shuffle(it)
201-
return self._new(it)
202-
203-
def concat(self): return self._new(itertools.chain.from_iterable(self.map(L)))
204-
def reduce(self, f, initial=None): return reduce(f, self) if initial is None else reduce(f, self, initial)
205-
def sum(self): return self.reduce(operator.add, 0)
206-
def product(self): return self.reduce(operator.mul, 1)
207-
def setattrs(self, attr, val): [setattr(o,attr,val) for o in self]
208-
209-
# %% ../nbs/02_foundation.ipynb
210-
add_docs(L,
211-
__getitem__="Retrieve `idx` (can be list of indices, or mask, or int) items",
212-
range="Class Method: Same as `range`, but returns `L`. Can pass collection for `a`, to use `len(a)`",
213-
split="Class Method: Same as `str.split`, but returns an `L`",
214-
splitlines="Class Method: Same as `str.splitlines`, but returns an `L`",
215-
copy="Same as `list.copy`, but returns an `L`",
216-
sorted="New `L` sorted by `key`, using `sort_ex`. If key is str use `attrgetter`; if int use `itemgetter`",
217-
unique="Unique items, in stable order",
218-
val2idx="Dict from value to index",
219-
filter="Create new `L` filtered by predicate `f`, passing `args` and `kwargs` to `f`",
220-
argwhere="Like `filter`, but return indices for matching items",
221-
argfirst="Return index of first matching item",
222-
map="Create new `L` with `f` applied to all `items`, passing `args` and `kwargs` to `f`",
223-
map_first="First element of `map_filter`",
224-
map_dict="Like `map`, but creates a dict from `items` to function results",
225-
starmap="Like `map`, but use `itertools.starmap`",
226-
itemgot="Create new `L` with item `idx` of all `items`",
227-
attrgot="Create new `L` with attr `k` (or value `k` for dicts) of all `items`.",
228-
cycle="Same as `itertools.cycle`",
229-
enumerate="Same as `enumerate`",
230-
renumerate="Same as `renumerate`",
231-
groupby="Same as `fastcore.basics.groupby`",
232-
zip="Create new `L` with `zip(*items)`",
233-
zipwith="Create new `L` with `self` zip with each of `*rest`",
234-
map_zip="Combine `zip` and `starmap`",
235-
map_zipwith="Combine `zipwith` and `starmap`",
236-
concat="Concatenate all elements of list",
237-
shuffle="Same as `random.shuffle`, but not inplace",
238-
reduce="Wrapper for `functools.reduce`",
239-
sum="Sum of the items",
240-
product="Product of the items",
241-
setattrs="Call `setattr` on all items")
242-
243160
# %% ../nbs/02_foundation.ipynb
244161
# Here we are fixing the signature of L. What happens is that the __call__ method on the MetaClass of L shadows the __init__
245162
# giving the wrong signature (https://stackoverflow.com/questions/49740290/call-from-metaclass-shadows-signature-of-init).
@@ -249,6 +166,191 @@ def _f(items=None, *rest, use_list=False, match=None): ...
249166
# %% ../nbs/02_foundation.ipynb
250167
Sequence.register(L);
251168

169+
# %% ../nbs/02_foundation.ipynb
170+
@patch
171+
def unique(self:L, sort=False, bidir=False, start=None):
172+
"Unique items, in stable order"
173+
return L(uniqueify(self, sort=sort, bidir=bidir, start=start))
174+
175+
# %% ../nbs/02_foundation.ipynb
176+
@patch
177+
def val2idx(self:L):
178+
"Dict from value to index"
179+
return val2idx(self)
180+
181+
# %% ../nbs/02_foundation.ipynb
182+
@patch(cls_method=True)
183+
def split(cls:L, s, sep=None, maxsplit=-1):
184+
"Class Method: Same as `str.split`, but returns an `L`"
185+
return cls(s.split(sep,maxsplit))
186+
187+
# %% ../nbs/02_foundation.ipynb
188+
@patch(cls_method=True)
189+
def splitlines(cls:L, s, keepends=False):
190+
"Class Method: Same as `str.splitlines`, but returns an `L`"
191+
return cls(s.splitlines(keepends))
192+
193+
# %% ../nbs/02_foundation.ipynb
194+
@patch
195+
def groupby(self:L, key, val=noop):
196+
"Same as `fastcore.basics.groupby`"
197+
return groupby(self, key, val=val)
198+
199+
# %% ../nbs/02_foundation.ipynb
200+
@patch
201+
def filter(self:L, f=noop, negate=False, **kwargs):
202+
"Create new `L` filtered by predicate `f`, passing `args` and `kwargs` to `f`"
203+
return self._new(filter_ex(self, f=f, negate=negate, gen=False, **kwargs))
204+
205+
# %% ../nbs/02_foundation.ipynb
206+
@patch(cls_method=True)
207+
def range(cls:L, a, b=None, step=None):
208+
"Class Method: Same as `range`, but returns `L`. Can pass collection for `a`, to use `len(a)`"
209+
return cls(range_of(a, b=b, step=step))
210+
211+
# %% ../nbs/02_foundation.ipynb
212+
@patch
213+
def argwhere(self:L, f, negate=False, **kwargs):
214+
"Like `filter`, but return indices for matching items"
215+
return self._new(argwhere(self, f, negate, **kwargs))
216+
217+
# %% ../nbs/02_foundation.ipynb
218+
@patch
219+
def enumerate(self:L):
220+
"Same as `enumerate`"
221+
return L(enumerate(self))
222+
223+
# %% ../nbs/02_foundation.ipynb
224+
@patch
225+
def renumerate(self:L):
226+
"Same as `renumerate`"
227+
return L(renumerate(self))
228+
229+
# %% ../nbs/02_foundation.ipynb
230+
@patch
231+
def argfirst(self:L, f, negate=False):
232+
"Return index of first matching item"
233+
if negate: f = not_(f)
234+
return first(i for i,o in self.enumerate() if f(o))
235+
236+
# %% ../nbs/02_foundation.ipynb
237+
@patch
238+
def map(self:L, f, *args, **kwargs):
239+
"Create new `L` with `f` applied to all `items`, passing `args` and `kwargs` to `f`"
240+
return self._new(map_ex(self, f, *args, gen=False, **kwargs))
241+
242+
# %% ../nbs/02_foundation.ipynb
243+
@patch
244+
def starmap(self:L, f, *args, **kwargs):
245+
"Like `map`, but use `itertools.starmap`"
246+
return self._new(itertools.starmap(partial(f,*args,**kwargs), self))
247+
248+
# %% ../nbs/02_foundation.ipynb
249+
@patch
250+
def map_dict(self:L, f=noop, *args, **kwargs):
251+
"Like `map`, but creates a dict from `items` to function results"
252+
return {k:f(k, *args,**kwargs) for k in self}
253+
254+
# %% ../nbs/02_foundation.ipynb
255+
@patch
256+
def zip(self:L, cycled=False):
257+
"Create new `L` with `zip(*items)`"
258+
return self._new((zip_cycle if cycled else zip)(*self))
259+
260+
# %% ../nbs/02_foundation.ipynb
261+
@patch
262+
def map_zip(self:L, f, *args, cycled=False, **kwargs):
263+
"Combine `zip` and `starmap`"
264+
return self.zip(cycled=cycled).starmap(f, *args, **kwargs)
265+
266+
# %% ../nbs/02_foundation.ipynb
267+
@patch
268+
def zipwith(self:L, *rest, cycled=False):
269+
"Create new `L` with `self` zip with each of `*rest`"
270+
return self._new([self, *rest]).zip(cycled=cycled)
271+
272+
# %% ../nbs/02_foundation.ipynb
273+
@patch
274+
def map_zipwith(self:L, f, *rest, cycled=False, **kwargs):
275+
"Combine `zipwith` and `starmap`"
276+
return self.zipwith(*rest, cycled=cycled).starmap(f, **kwargs)
277+
278+
# %% ../nbs/02_foundation.ipynb
279+
@patch
280+
def itemgot(self:L, *idxs):
281+
"Create new `L` with item `idx` of all `items`"
282+
x = self
283+
for idx in idxs: x = x.map(itemgetter(idx))
284+
return x
285+
286+
# %% ../nbs/02_foundation.ipynb
287+
@patch
288+
def attrgot(self:L, k, default=None):
289+
"Create new `L` with attr `k` (or value `k` for dicts) of all `items`."
290+
return self.map(lambda o: o.get(k,default) if isinstance(o, dict) else nested_attr(o,k,default))
291+
292+
# %% ../nbs/02_foundation.ipynb
293+
@patch
294+
def sorted(self:L, key=None, reverse=False, cmp=None, **kwargs):
295+
"New `L` sorted by `key`, using `sort_ex`. If key is str use `attrgetter`; if int use `itemgetter`"
296+
return self._new(sorted_ex(self, key=key, reverse=reverse, cmp=cmp, **kwargs))
297+
298+
# %% ../nbs/02_foundation.ipynb
299+
@patch
300+
def concat(self:L):
301+
"Concatenate all elements of list"
302+
return self._new(itertools.chain.from_iterable(self.map(L)))
303+
304+
# %% ../nbs/02_foundation.ipynb
305+
@patch
306+
def copy(self:L):
307+
"Same as `list.copy`, but returns an `L`"
308+
return self._new(self.items.copy())
309+
310+
# %% ../nbs/02_foundation.ipynb
311+
@patch
312+
def cycle(self:L):
313+
"Same as `itertools.cycle`"
314+
return cycle(self)
315+
316+
# %% ../nbs/02_foundation.ipynb
317+
@patch
318+
def shuffle(self:L):
319+
"Same as `random.shuffle`, but not inplace"
320+
it = copy(self.items)
321+
random.shuffle(it)
322+
return self._new(it)
323+
324+
# %% ../nbs/02_foundation.ipynb
325+
@patch
326+
def reduce(self:L, f, initial=None):
327+
"Wrapper for `functools.reduce`"
328+
return reduce(f, self) if initial is None else reduce(f, self, initial)
329+
330+
# %% ../nbs/02_foundation.ipynb
331+
@patch
332+
def sum(self:L):
333+
"Sum of the items"
334+
return self.reduce(operator.add, 0)
335+
336+
# %% ../nbs/02_foundation.ipynb
337+
@patch
338+
def product(self:L):
339+
"Product of the items"
340+
return self.reduce(operator.mul, 1)
341+
342+
# %% ../nbs/02_foundation.ipynb
343+
@patch
344+
def map_first(self:L, f=noop, g=noop, *args, **kwargs):
345+
"First element of `map_filter`"
346+
return first(self.map(f, *args, **kwargs), g)
347+
348+
# %% ../nbs/02_foundation.ipynb
349+
@patch
350+
def setattrs(self:L, attr, val):
351+
"Call `setattr` on all items"
352+
[setattr(o,attr,val) for o in self]
353+
252354
# %% ../nbs/02_foundation.ipynb
253355
def save_config_file(file, d, **kwargs):
254356
"Write settings dict to a new config file, or overwrite the existing one."

0 commit comments

Comments
 (0)