How did the inspect module make it seem like an argument doesn't have a default (though it does), and what would be the reason for doing this (if at all any)?
The help of inspect.Signature shows return_annotation
argument without a default:
>>> import inspect
>>> help(inspect.Signature)
(...)
class Signature(builtins.object)
| Signature(parameters=None, *, return_annotation, __validate_parameters__=True)
(...)
Yet one can construct a Signature with only one argument:
>>> sig = inspect.Signature(None)
>>> # Nothing bad happens
This seems to violate the rules. So looking at the code for the Signature
class, I see:
def __init__(self, parameters=None, *, return_annotation=_empty, __validate_parameters__=True)
Alright, return_annotation
does have a default after all (which is why inspect.Signature(None)
works).
So the questions are:
How did the inspect module achieve this trickery? Is there a good rational for doing so?
Apparently, help
calls inspect.signature(object)
under the hood, where object
is the function. This treats the inspect.Signature.empty
default argument in such a way that it's shown as having no default value at all.
Another example:
>>> def thing(self, a=inspect.Signature.empty):
... ...
...
>>> help(thing)
Help on function thing in module __main__:
thing(self, a) # Here it is!
You can see what the help
function does under the hood by running this:
import trace
trace.Trace().runfunc(help, thing)
For me (Python 3.6) it shows this:
<snip>
pydoc.py(1357): try:
pydoc.py(1358): signature = inspect.signature(object)
--- modulename: inspect, funcname: signature
inspect.py(3002): return Signature.from_callable(obj, follow_wrapped=follow_wrapped)
--- modulename: inspect, funcname: from_callable
inspect.py(2751): return _signature_from_callable(obj, sigcls=cls,
<snip>
pydoc.py(1361): if signature:
pydoc.py(1362): argspec = str(signature)
If you replicate this in your code, you'll get this:
>>> inspect.signature(thing)
<Signature (self, a)>
>>> str(_)
'(self, a)' # huh?!