允许help()处理部分函数对象

dur*_*2.0 6 python

我正在尝试确保help()在Python 2.7上运行REPL显示包含__doc__的函数functools.partial.目前运行help()在一个functools.partial"功能"显示__doc__的的functools.partial类,而不是我的包裹功能的__doc__.有没有办法实现这个目标?

考虑以下callables:

def foo(a):
    """My function"""
    pass

partial_foo = functools.partial(foo, 2)
Run Code Online (Sandbox Code Playgroud)

跑步help(foo)将导致显示foo.__doc__.但是,运行help(partial_foo)结果__doc__Partial对象.

我的第一个方法是使用functools.update_wrapper其正确替换部分对象的__doc__foo.__doc__.但是,由于pydoc的原因,这并不能解决"问题" .

我已经调查了pydoc代码,问题似乎partial_foo是实际上是一个Partial对象而不是典型的函数/可调用,有关该细节的更多信息,请参阅此问题.

默认情况下,pydoc将显示__doc__对象类型,而不是实例,如果传递的对象被inspect.isclass确定为类.有关代码本身的更多信息,请参阅render_doc函数.

所以,在上面的场景中,pydoc显示了类型的帮助,而functools.partial不是__doc__我的functools.partial实例.

反正有没有改变我的调用help()functools.partial传递的实例,help()以便它将显示__doc__实例,而不是类型?

dur*_*2.0 2

我找到了一个非常古怪的方法来做到这一点。我编写了以下函数来覆盖该__builtins__.help函数:

def partialhelper(object=None):
    if isinstance(object, functools.partial):
        return pydoc.help(object.func)
    else:
        # Preserve the ability to go into interactive help if user calls
        # help() with no arguments.
        if object is None:
            return pydoc.help()
        else:
            return pydoc.help(object)
Run Code Online (Sandbox Code Playgroud)

然后只需在 REPL 中将其替换为:

__builtins__.help = partialhelper
Run Code Online (Sandbox Code Playgroud)

这很有效,而且似乎还没有任何重大缺点。但是,上述简单的实现没有办法支持仍然显示__doc__某些对象 functools.partial。它要么全有,要么全无,但可能会向包装的(原始)函数附加一个属性,以指示原始函数是否__doc__应显示原始函数。然而,在我的场景中,我永远不想这样做。

请注意,使用 IPython 和嵌入功能时,上述内容不起作用。这是因为 IPython 直接通过引用 'real' 来设置 shell 的命名空间__builtin__,请参阅代码和旧邮件列表以获取有关原因的信息。

因此,经过一番调查后,还有另一种方法可以将其侵入 IPython。我们必须重写该类site._Helper,IPython 使用该类来显式设置帮助系统。以下代码将在调用 BEFORE 时执行此操作IPython.embed

import site
site._Helper.__call__ = lambda self, *args, **kwargs: partialhelper(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

我在这里还缺少其他缺点吗?