What are the five inspect.Parameter kinds, and what does each allow at a call site?
answer
- Five values on one enum
- How an argument may be supplied
- Slash and star split the groups
- Two of them are catch-alls
- Positional-only through var-keyword, in order
basics
~20 sinspect.Parameter has five kinds: POSITIONAL_ONLY, POSITIONAL_OR_KEYWORD, VAR_POSITIONAL, KEYWORD_ONLY and VAR_KEYWORD. The kind says how an argument may be supplied — by position, by either, by name only, or swept into a catch-all — and .parameters lists them in that order.
solid answer
~40 sEvery `inspect.Parameter` carries a `.kind`. `POSITIONAL_ONLY` — declared before a `/` — can only be filled by position, so a name-based injector can never supply it. `POSITIONAL_OR_KEYWORD` is the ordinary case and the only kind fillable either way. `VAR_POSITIONAL` is the single `*args` parameter: it appears as **one** entry in `.parameters`, not as a slot to fill. `KEYWORD_ONLY` — anything after `*` or after `*args` — must be passed by name. `VAR_KEYWORD` is the `**kwargs` catch-all. `.parameters` iterates in declaration order, which the grammar forces to be exactly that kind order, so comparing `p.kind is inspect.Parameter.KEYWORD_ONLY` while iterating is enough to classify a callable. Tools that supply arguments by name — dependency containers, CLI generators, serializers — treat only POSITIONAL_OR_KEYWORD and KEYWORD_ONLY as fillable slots.
code
python · 7 linesimport inspect
def collect(source, /, window=60, *samples, sink, **tags):
return source
for p in inspect.signature(collect).parameters.values():
print(f"{p.name:8} {p.kind.name}")go deeper
Learn the five names and the syntax that produces each: before a slash, ordinary, star-args, after the star, and double-star. Being able to point at a def and say which parameter is which kind is the expected level.
Explain what each kind permits at the call site and why the two variadic kinds are single entries rather than slots. Interviewers expect you to write the loop that picks out the parameters a framework could fill by name.
Demonstrate handling the awkward cases in real code: callables mixing positional-only and variadic parameters, deciding whether to reject or adapt, and producing an error message that tells the caller which parameter could not be supplied and why.
Weigh how much freedom your framework's public callables should have. Accepting every parameter kind means carrying adapter code forever; constraining handlers to keyword-fillable parameters is a one-line rule that removes a whole class of support burden.
## The kind is the whole point of Parameter A parameter's name and default are easy; the field that carries the real information is `.kind`. It answers the only question a caller — human or framework — actually needs answered: *how am I allowed to supply this?* There are exactly five answers, and they are class attributes on `inspect.Parameter`. ### POSITIONAL_ONLY Declared by putting a `/` after the parameter in the `def`. It can be filled by position and by nothing else; passing it by name is a `TypeError`, and the name is free for reuse inside `**kwargs`. Historically these only showed up on C-implemented builtins, which is why introspection code that predates the `/` syntax often ignored the kind entirely. For a framework the consequence is sharp: **a name-based injector cannot fill a positional-only parameter at all**, so it must either supply it positionally or refuse the callable. ### POSITIONAL_OR_KEYWORD The default kind — every ordinary parameter with no `/` or `*` around it. It may be supplied either way, which is exactly why binding real arguments needs machinery: the same value can arrive as `args[0]` or as `kwargs["sensor_id"]`, and code that reads only one of those is wrong half the time. ### VAR_POSITIONAL The `*args` parameter. There is at most one, and the crucial reflection fact is that it is **one entry** in `.parameters` whose name is `args` (or whatever you called it) — it is not a variable number of entries, and it tells you nothing about how many extra positionals a caller might pass. Its `.default` is always `empty`; it is never "required" in the missing-argument sense, because supplying zero extras is legal. ### KEYWORD_ONLY Anything declared after a bare `*` or after `*args`. It must be passed by name. It may or may not have a default — those two properties are independent, and conflating them is a common mistake: `def f(*, timeout)` is keyword-only *and* required. ### VAR_KEYWORD The `**kwargs` catch-all, again at most one and again a single `.parameters` entry. Its presence is the signal that the callable will tolerate arbitrary extra keyword names — which is how a serializer or a config loader decides whether it is safe to splat a dict of unknown keys into the call. ## Ordering is guaranteed `.parameters` iterates in declaration order, and Python's grammar constrains declaration order to be exactly the kind order listed above. So the sequence you see is always positional-only, then positional-or-keyword, then the single var-positional, then keyword-only, then the single var-keyword. That is why so much introspection code is a single `for p in sig.parameters.values():` loop with a `match`/`if` on `p.kind` — you never have to sort. The kinds are enum members, so compare them with `is` against `inspect.Parameter.POSITIONAL_ONLY` and friends rather than against their names or integer values. ## What the kinds mean for framework code The practical algorithm nearly every argument-supplying tool runs is: 1. Walk `sig.parameters.values()`. 2. Skip `VAR_POSITIONAL` and `VAR_KEYWORD` — they are not slots, they are policies about surplus. 3. For `POSITIONAL_OR_KEYWORD` and `KEYWORD_ONLY`, look up a value by name (from a container, a request body, a CLI namespace, a config file). 4. For `POSITIONAL_ONLY`, either build the positional list carefully or reject the callable with a clear error. 5. Treat `.default is inspect.Parameter.empty` as "this one is mandatory; fail loudly if I cannot supply it". That five-line algorithm is what an interviewer is really checking for. Candidates who can recite the five names but cannot say which are fillable by name have memorised a list rather than understood the model. ## Small details worth having * `str(param)` renders the parameter the way it would appear in a `def`, including the annotation and default — handy for error messages. * A `Parameter` object knows its kind but not its position; position comes from the ordering of `.parameters`. * `Parameter.replace(kind=...)` exists, and constructing a `Signature` from hand-built `Parameter` objects will reject a sequence whose kinds are out of order. ## The kinds show up in your error messages When argument supply fails, the kind is what makes an error message useful. "Cannot inject 'reading': it is positional-only" tells a caller exactly what to change; "missing argument" does not. Since `str(param)` renders each parameter as it would appear in a `def`, the usual pattern is to name the offending parameter, print its rendered form, and say which kinds your framework can fill. The same information decides your policy on surplus: a callable with no VAR_KEYWORD parameter must be called with exactly the names it declares, so unknown keys are an error to report rather than extras to pass along.
- Why can a name-based dependency injector never fill a POSITIONAL_ONLY parameter?Because the interpreter rejects it by name. A positional-only parameter is matched purely by position, and passing its name raises `TypeError` — the name is even free to reappear inside `**kwargs`. An injector that only knows how to say `func(**values)` therefore has to build a positional list for those parameters or refuse the callable outright with a clear error.
- How many entries does .parameters have for a function declared with *args and **kwargs?One each. `*args` is a single `Parameter` of kind VAR_POSITIONAL and `**kwargs` a single one of kind VAR_KEYWORD, regardless of how many extra arguments a caller eventually passes. A `Signature` describes the declaration, never a particular call, so nothing in it varies with call-site usage.
- How would you detect that a callable tolerates arbitrary extra keyword arguments?Look for a parameter whose `.kind is inspect.Parameter.VAR_KEYWORD` in `sig.parameters.values()`. Its presence means surplus keyword names are swept up rather than rejected, so it is safe to splat a dict of unknown keys. Without one, any name not matching a declared parameter raises `TypeError` at the call.
saying these in an interview costs you the question
- Thinks *args and **kwargs are absent from .parameters
- Says positional-only parameters can be passed by name
- Counts each surplus argument as its own Parameter entry
- Confuses KEYWORD_ONLY with 'has a default value'
- Believes .parameters iterates in alphabetical order
- Compares p.kind against a string instead of the enum member