Reputation: 2282
I'm having trouble figuring out how I should be building a signature manually. The docs say that the parameters
argument of inspect.Signature
should be an OrderedDict
. But that fails for me.
Even the parameters
in an inspect.Signature
instance, returned by the inspect.signature
function don't play well as an __init__
argument:
>>> from inspect import Signature, signature
>>> def f(a, b: int, c=0, d: float=0.0): ...
...
>>> Signature(signature(f).parameters)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/twhalen/.pyenv/versions/3.8.2/lib/python3.8/inspect.py", line 2775, in __init__
kind = param.kind
AttributeError: 'str' object has no attribute 'kind'
But Signature(signature(f).parameters.values())
works fine. Yet type(signature(f).parameters.values())
tells me it's an odict_values
, not an OrderedDict
as the docs say.
How should one construct a parameters
argument for inspect.Signature
?
Is the misalignment between inspect
's documentation and the truth of the code just that, or is there some profound reason I'm missing?
Upvotes: 4
Views: 1877
Reputation: 114240
You are missing something important (but not very profound). The documentation for the class attribute parameters
reads
An ordered mapping of parameters’ names to the corresponding
Parameter
objects. Parameters appear in strict definition order, including keyword-only parameters.
However this the output of the class initializer. The documentation for the __init__
argument parameters
reads:
The optional parameters argument is a sequence of
Parameter
objects, which is validated to check that there are no parameters with duplicate names, and that the parameters are in the right order, i.e. positional-only first, then positional-or-keyword, and that parameters with defaults follow parameters without defaults.
The input is expected to be a sequence, not a mapping. The output is an ordered mapping in the Signature
object. The Signature
class is really not meant to be initialized "by hand" unless you have a special case where you need to.
The type odict_values
represents the result of a call to OrderedDict.values
. It is a sequence, which is why that particular call works. You can print the ordered dictionary to get a better sense of what's happening:
>>> signature(f).parameters
mappingproxy(OrderedDict([('a', <Parameter "a">), ('b', <Parameter "b: int">), ('c', <Parameter "c=0">), ('d', <Parameter "d: float = 0.0">)]))
You can ignore the mappingproxy
: it just makes the whole thing read-only. Signature
's initializer does not need the mapping because Parameter
objects already contain the name of the parameter.
Upvotes: 2