这个答案描述了我如何找到一个合理的解决方案,所以请耐心等待,或者直接滚动到最后的 TL;DR'd 装饰器。
让我们首先看看什么help https://docs.python.org/3/library/functions.html#help是并且确实是。help
通过以下方式添加到内置命名空间site https://docs.python.org/3/library/site.html。我的 Ubuntu 机器上的默认实现将所有内容重定向到pydoc.help https://docs.python.org/3/library/pydoc.html。这又使用inspect https://docs.python.org/3/library/inspect.html获取签名和描述。您只对函数感兴趣,更具体地说__init__
。另外,您只关心签名,而不关心文档的其余部分。这应该会让事情变得更简单。
我们可以放心地假设您在中看到的签名help
/pydoc
是由生成的inspect.signature https://docs.python.org/3/library/inspect.html#inspect.signature。看着源代码 https://github.com/python/cpython/blob/v3.8.2/Lib/inspect.py#L3091Python 3.8.2 的该函数,并跟踪inspect.Signature.from_callable https://github.com/python/cpython/blob/v3.8.2/Lib/inspect.py#L2840 -> inspect._signature_from_callable https://github.com/python/cpython/blob/v3.8.2/Lib/inspect.py#L2206 -> 2246号线 https://github.com/python/cpython/blob/v3.8.2/Lib/inspect.py#L2246,我们看到了一个可能的解决方案。
它的要点是,如果一个函数对象有一个__signature__
属性,并且该属性是一个实例inspect.Signature https://docs.python.org/3/library/inspect.html#inspect.Signature,它将用作函数的签名,而无需从正常检查中重新计算__code__ https://docs.python.org/3/library/inspect.html#types-and-members and __annotation__
对象。
我们赞成的另一点是函数是具有__dict__ https://docs.python.org/3/library/stdtypes.html#object.__dict__可以为其分配任意键的属性。分配__signature__
添加到您的函数不会影响其执行,因为它仅用于检查。实际的运行时签名是在__code__
对象通过属性如co_argcount
, co_kwonlyargcount
, co_varnames
, etc.
因此你可以这样做:
import inspect
Child2.__init__.__signature__ = inspect.signature(Base.__init__)
结果:
>>> help(Child1)
Help on class Child1 in module __main__:
class Child1(Base)
| Child1(arg1, arg2)
|
| Method resolution order:
| Child1
| Base
| builtins.object
|
| Methods defined here:
|
| foo(self)
|
| ----------------------------------------------------------------------
| Methods inherited from Base:
|
| __init__(self, arg1, arg2)
| Initialize self. See help(type(self)) for accurate signature.
|
| ----------------------------------------------------------------------
| Data descriptors inherited from Base:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
>>> help(Child2)
Help on class Child2 in module __main__:
class Child2(Base)
| Child2(arg1, arg2)
|
| Method resolution order:
| Child2
| Base
| builtins.object
|
| Methods defined here:
|
| __init__(self, arg1, arg2)
| Initialize self. See help(type(self)) for accurate signature.
|
| foo(self)
|
| ----------------------------------------------------------------------
| Data descriptors inherited from Base:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
除此之外,两个构造函数都继续照常运行。
由于这不会修改代码对象甚至注释,因此更改不太可能影响函数操作。
TL;DR
这是一个装饰器,您可以使用它来复制函数签名,而不会以任何其他方式干扰该函数:
import inspect
def copy_signature(base):
def decorator(func):
func.__signature__ = inspect.signature(base)
return func
return decorator
你可以重写Child2
as
class Child2:
@copy_signature(Base.__init__)
def __init__(self, *args, **kwargs):
...