Here’s a simple implementation of the syntax I suggested above.
Since in practically all use cases a piped object would be passed as either the first or the second argument I decided to simply use the >>
operator to denote passing the object as a second argument to avoid specifying the position with a sentinel object:
class pipe:
def __init__(self, obj):
self.obj = obj
def __or__(self, func):
return pipe(func(self.obj))
class using:
def __init__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
def __rlshift__(self, func):
return lambda obj: func(obj, *self.args, **self.kwargs)
def __rrshift__(self, func):
first, *rest = self.args
return lambda obj: func(first, obj, *rest, **self.kwargs)
Sample usage:
from itertools import batched
pipe('abcde') | batched << using(2) | map >> using(''.join) | list | print
# outputs ['ab', 'cd', 'e']