Currently inspect.Parameter
, that is used by inspect.signature
and, as a consequence, in pydoc
to represent function parameters, uses plain repr()
to provide a string representation of its default
value, which can be bulky and not very informative for some objects. Consider the following (not intended to be real use-case) example that tries to cover some cases (both realistic and added rather for concept demonstration):
import _random
import builtins
import re
import inspect
class A:
class B:
def bar(self):
pass
def foo(self):
pass
class MyList(list):
pass
def g():
def h():
pass
return h
h = g()
def f(a=print, b=re.compile, c=_random.Random().seed, d=A,
e=A(), f=A.foo, g=A().foo, h=A.B, i=A.B(), j=A.B.bar, k=A.B().bar,
l=MyList([1, 2, 3]), m=re, n=builtins, o=SyntaxError, p=lambda x: x, q=h):
pass
print(inspect.signature(f))
(a=<built-in function print>, b=<function compile at 0x7f6f490fd080>,
c=<built-in method seed of _random.Random object at 0x55998bdd4a20>,d=<class '__main__.A'>,
e=<__main__.A object at 0x7f6f491244d0>, f=<function A.foo at 0x7f6f4911ab60>,
g=<bound method A.foo of <__main__.A object at 0x7f6f49124510>>, h=<class '__main__.A.B'>,
i=<__main__.A.B object at 0x7f6f49124590>, j=<function A.B.bar at 0x7f6f4911ac00>,
k=<bound method A.B.bar of <__main__.A.B object at 0x7f6f491245d0>>,
l=[1, 2, 3], m=<module 're' from '/usr/local/lib/python3.11/re/__init__.py'>, n=<module 'builtins' (built-in)>,
o=<class 'SyntaxError'>, p=<function <lambda> at 0x7f6f4911ade0>, q=<function g.<locals>.h at 0x7f6f4911ad40>)
The function/object addresses, mentions of value kind (class, object, built-in method, bound method etc) and module paths doesn’t provide any useful information in context of interactive documentation, but make output much longer.
No information is provided about the nature of compile
function.
Also no difference is made between the subclass that doesn’t implement its own __repr__
(MyList
) and its base class, but maybe in this case the code that renders default value shouldn’t try to be smarter that programmer and just use __repr__
of base class as it does now.
Here is an output with the solution I tried to implement:
(a=builtins.print, b=re.compile,
c=_random.Random().seed, d=__main__.A,
e=__main__.A(), f=__main__.A.foo,
g=__main__.A().foo, h=__main__.A.B,
i=__main__.A.B(), j=__main__.A.B.bar,
k=__main__.A.B().bar, l=__main__.MyList(),
m=re, n=builtins, o=builtins.SyntaxError,
p=__main__.<lambda>, q=__main__.g.<locals>.h)
There are cases that may be more difficult to handle, like built-in types that provide their own __repr__
but do not belong to builtins
:
import inspect
import re
m = re.compile(r"[_\w\d]+")
def f(x=m):
pass
print(m)
print(inspect.signature(f))
re.compile('[_\\w\\d]+')
(x=re.Pattern())