Description
Feature or enhancement
Proposal:
from functools import partial, Placeholder
def foo(a):
return None
# Now
partial(foo, Placeholder) # TypeError
# After
partial(foo, Placeholder) # Success
# Also, converts all Placeholder arguments to positional only
1. Rationale
So, I considered automatic trimming of trailing Placeholder
s instead of forbidding such. However it didn't sit well with me.
So I thought this over. Not having trailing Placeholders
works well, however both approaches of achieving this have flaws:
a) Forbidding them - results in unexpected errors for the user.
b) Trimming automatically - obfuscates inner workings by implicit input modifications.
Furthermore, it sometimes could be desired to have a trailing Placeholder
to convert argument to positional only.
So I think it would be best not to have this restriction at all. This makes things more explicit and predictable. E.g. both would work:
class A:
def func(self, a):
pass
p1 = partial(func)
p2 = partial(func, Placeholder)
And as expected, self
of p1
can be both positional or keyword, while self
of p2
becomes restricted to positional only.
2. Implementation
This simplifies the code by not having to do error checks or trimming routines. Existing implementation handles trailing placeholders without modifications (except minor Fast Path fix in C).
3. Relation to partialmethod
This has come out during #124788, but it turned out to be orthogonal.
partialmethod
stays as it was before - if no positionals provided argument kind
of self
is unaffected, while if args
are provided then self
becomes positional only.
4. Performance
Slightly faster for both cases (with and without Placeholders) when merging args of previous partial
with new args.
S="
from functools import partial, Placeholder
def f(a, b):
pass
p1 = partial(f, 1, 2)
p2 = partial(f, Placeholder, 2)
"
C0='partial(f)'
C1='partial(f, 1, 2)'
C2='partial(p1, 1, 2)'
C3='partial(p2, 1, 2)'
# BEFORE | AFTER
$PYEXE -m timeit -s $S $C0 # 135 ns | 135 ns
$PYEXE -m timeit -s $S $C1 # 170 ns | 170 ns
$PYEXE -m timeit -s $S $C2 # 195 ns | 165 ns
$PYEXE -m timeit -s $S $C3 # 195 ns | 165 ns
I think this is more flexible, simple and "straight" (I.e. If base logic is understood, the implications are clear and behaviour is predictable).
Has this already been discussed elsewhere?
This is a minor feature, which does not need previous discussion elsewhere
Or to be more precise, this is an update for new unreleased functionality.
Links to previous discussion of this feature:
No response