In _PyEval_Vector, positional and keyword argument values are converted to _PyStackRef in separate loops. Both loops call PyStackRef_FromPyObjectNew.
The values are consecutive in args, and total_args already includes both groups. I replaced the two loops locally with:
for (size_t i = 0; i < total_args; i++) {
arguments[i] = PyStackRef_FromPyObjectNew(args[i]);
}
This removes the duplicated conversion code and the second kwnames check. Conversion order and reference ownership stay the same. _PyEvalFramePushAndInit still receives the positional count, argcount, and kwnames separately.
The test suite passes with the change.
Is there a reason to keep the positional and keyword conversions separate?
P.S. Even with -O3 -march=native, the compiler (gcc-16 and clang-23) leaves these as two separate loops in the optimized IR (LLVM IR | GCC GIMPLE), including the second kwnames check and keyword-count load. This suggests a small performance optimization opportunity, rather than just a source-code cleanup.