So Iāve had a read through this and I think the proposal has ended up overly complex and a bit off track.
So here is my more focused suggestion. For the context of why this function would be useful you can read the many examples here Introduce funnel operator i,e '|>' to allow for generator pipelines - #166 by jamsamcam
So if we strip this function to its conceptual core we are trying to construct an array of partials which are then wrapped in a function which takes an item through each partial passing the item from the last step through all of them until its transformed into the final result (basically a bit like reduce)
If we keep it simple and follow convention over configuration we can say that each function will be passed the item as the last element in itās list of *args.
We can declare such a function like so
def pipe(*funcs):
return lambda initial_value: reduce(lambda acc, func: func(acc), funcs, initial_value)
item_pipeline = pipe(
partial(map, lambda a: item.name),
partial(filter, lambda b: ādelete redā not in b),
list
)
processed_items = item_pipeline(items)
This gives us a pretty good default pipe function using existing concepts form the functool library wihtout massively complex implementations.
Providing a simple implementation like this could be a nice convenience for people who donāt want to declare this in all of their projects or import complicated pipe library and doesnāt feel like a huge cost to functools
In that conversaion people also mentioned they wished to have the result of the pipe to be on the right hand side, for this we can use a context manager based object:
class pipe:
def __init__(self, *funcs):
self.funcs = funcs
self.result = None
def __call__(self, initial_value):
"""Allows direct invocation like a function."""
return reduce(lambda acc, func: func(acc), self.funcs, initial_value)
def __enter__(self):
"""Context manager entry ā simply return the result."""
return self.result
def __exit__(self, exc_type, exc_val, exc_tb):
"""Context manager exit ā nothing special needed."""
pass
def __getitem__(self, initial_value):
"""Allows `with p(6) as result:` syntax."""
self.result = self(initial_value)
return self
p = pipe([
lambda x: x + 2,
lambda x: x * 3,
lambda x: x - 1
])
# As a callable:
print(p(5)) # Output: 20
# As a context manager:
with p(6) as result:
print(result) # Output: 23
In this case we can pretty much get that syntax without declaring that much python code, I think if the initial version of this function is restricted to just this. This is powerful enough for most uses cases.
Dealing with arguments in different places etc can simply handled through passing in lambdas or partials.
If in the future special python syntax is added we can of course extend this object to support or indeed expose it as a native c class.
But for now I donāt thin the complexity is needed and would make it harder to justify including this function.