2 ms·
I wish Python had arrow operators like Clojure. Often times, chaining several functions leads to a mess like this: fun1(fun2(fun3(xyz, 10)), 12) I expect
by behnamoh 4y ago
I wish Python had arrow operators like Clojure. Often times, chaining several functions leads to a mess like this:
fun1(fun2(fun3(xyz, 10)), 12)
I expect it to be more like this:
xyz | fun3(_, 10) | fun2(_, 12) | fun1
Unfortunately, Python creators reserved "|" for dictionary merging :/
- elesiuta 4y agoThis sounded like it'd be fun to implement so I took a quick stab at it, it supports unpacking tuples to any number of _ in any position, including with kwargs. class Placeholder: def __init__(self) -> None: pass _ = Placeholder() class Arrow: def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): if not any(isinstance(arg, Placeholder) for arg in args) and \ not (kwargs and any(isinstance(arg, Placeholder) for arg in kwargs.values())): return self.func(*args, **kwargs) else: placeholder_indices = [i for i, arg in enumerate(args) if isinstance(arg, Placeholder)] placeholder_kwargs = {k: v for k, v in kwargs.items() if isinstance(v, Placeholder)} original_kwargs = {k: v for k, v in kwargs.items() if not isinstance(v, Placeholder)} def new_func(new_args): assert len(new_args) == len(placeholder_indices) + len(placeholder_kwargs), "ERROR: Wrong number of arguments" return self.func( *[new_args[placeholder_indices.index(i)] if i in placeholder_indices else arg for i, arg in enumerate(args)], **{k: new_args[len(placeholder_indices) + i] for i, k in enumerate(placeholder_kwargs)}, **original_kwargs) return Arrow(lambda *new_args: new_func(new_args)) def __ror__(self, other): if isinstance(other, tuple): return self.func(*other) return self.func(other) @Arrow def add(x, y, z): return x + y + z @Arrow def multiply(x, y): return x * y @Arrow def subtract(x, y): return x - y @Arrow def add_one(x): return x + 1 print((1, 5) | add(_, 3, _) | add_one | subtract(_, 2) | subtract(50, y=_))