I know this is old, but I run into this all the time, and I think I've created a neat solution. I use a slightly modified version of partial
that uses an Ellipses object (...
) as a placeholder value if you do not know it at the time that the object is built. It's quite useful for exactly this!
Here is the original __call__
method of partial
def __call__(self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(*self.args, *args, **keywords)
Instead, we can use the literal ...
as a special case to indicate a placeholder value
>>> type(...)
<class 'ellipsis'>
Here's the entire implementation:
class bind(partial):
"""
An improved version of partial which accepts Ellipsis (...) as a placeholder
"""
def __call__(self, *args, **keywords):
keywords = {**self.keywords, **keywords}
iargs = iter(args)
args = (next(iargs) if arg is ... else arg for arg in self.args)
return self.func(*args, *iargs, **keywords)
Usage is fairly straightforward
def foo(a, b, c, /, *, d):
print(f"A({a}) B({b}) C({c}) D({d})")
f1 = bind(foo, 1, 2, 3, d=4)
f1()
f2 = bind(foo, 1, 2, d=4)
f2(3)
f3 = bind(foo, 1, ..., 3, d=4)
f3(2)
f4 = bind(foo, ..., 2, ..., d=4)
f4(1, 3)
f5 = bind(foo, ..., d=5)
f5(1, 2, 3, d=4)