gh-150816: Speed up inspect.signature() for Python functions#150823
gh-150816: Speed up inspect.signature() for Python functions#150823gaborbernat wants to merge 3 commits into
Conversation
12b3b99 to
fafbd85
Compare
|
In order to keep the commit history intact, please avoid squashing or amending history and then force-pushing to the PR. Reviewers often want to look at individual commits. When the PR is merged, everything will be squashed into a single commit. |
skirpichev
left a comment
There was a problem hiding this comment.
Looks good, with few comments.
CC @sobolevn
Parameters built from a function's code object always have valid identifier
names and canonical kinds, yet each one is constructed through the validating
Parameter() constructor. Add Parameter._from_valid_args() for these trusted
callers to skip the redundant checks, inlining the comprehension implicit-arg
recast ('.N' -> 'implicitN', positional-only) that __init__ performs. The
public constructor and its validation are unchanged.
fafbd85 to
eb05e27
Compare
The inlined recast and deferring to __init__ for the rare '.0' comprehension argument perform identically, so keep the simpler version that does not duplicate __init__'s logic.
|
Good point — I benchmarked both: inlining the recast and deferring the rare |
_signature_from_function() also handles third-party function-like objects (is_duck_function), whose code object's co_varnames are not guaranteed to be valid identifiers. Route those through the validating Parameter() constructor; keep the _from_valid_args fast path only for real Python functions.
|
Good catch, thank you. You're right that Fixed in the latest commit: the |
|
@gaborbernat, please stop force-pushing. |
Sorry, I think those were my comments from yesterday, I added separate commit today. |
inspect.signature()builds aSignaturewhose everyParametergoes through the publicParameterconstructor, which validates the name and the kind on each call. When the parameters come from a function's own code object, the names are already valid identifiers and the kinds are already the canonical constants, so that validation re-checks facts that are guaranteed to hold. Signature introspection runs constantly across the ecosystem — web frameworks resolving view and dependency arguments,clickbuilding commands, pytest wiring fixtures, serialization and validation layers — usually once per function and often at import time while an application is assembled.This adds an internal
Parameter._from_valid_args()used only by_signature_from_function, the trusted caller that reads parameters from a code object. It populates the instance directly and skips the redundant checks. The one case that still needs the constructor's handling, a comprehension's implicit.0argument, is detected and deferred to it. The publicParameter()constructor and all of its validation are untouched, so every other caller behaves exactly as before.Taking the signature of 400 real callables collected from popular packages (
requests,click,jinja2,sqlalchemy,werkzeug,flaskand others) improves from 1.46 ms to 1.16 ms, 26% faster.Benchmark (pyperf)
Run base vs patched by swapping
Lib/inspect.pyon the same interpreter. The script collects callables from installed third-party packages when present and always includes several stdlib modules, so it runs with no extra installs.Resolves #150816.