如何让Python help()函数在应用装饰器时正常输出提示信息?
解决方法
这个问题的核心原因是help()的实现依赖pydoc模块生成提示内容,pydoc生成头部那行说明时会优先判断传入对象的实际类型:functools.lru_cache返回的_lru_cache_wrapper是C实现的内置可调用对象,哪怕它已经通过functools.wraps复制了原函数的名称、所属模块、文档字符串、参数签名,pydoc还是会把它识别为内置包装器,而非普通用户定义函数,所以才会出现Help on _lru_cache_wrapper的混淆提示。
两种成本极低的非侵入式方案都能解决这个问题:
- 单函数适配方案:写一个通用修正装饰器
写一个几行代码的小装饰器,套在lru_cache这类标准库装饰器外层,微调包装对象的类型标识,让pydoc把它识别为普通函数即可,不影响任何原有逻辑:
此时调用import functools import types def fix_pydoc_display(func): class _PatchedWrapper(type(func)): pass _PatchedWrapper.__name__ = "function" func.__class__ = _PatchedWrapper return func # 使用示例 @fix_pydoc_display @functools.lru_cache def myfunction(parameter=False) -> dict[str, str]: """Doc string of myfunction""" return {}help(myfunction),头部会正常显示Help on function myfunction in module 对应模块名,缓存逻辑、参数提示、文档内容都和原来完全一致。 - 全局适配方案:重写全局help函数
如果项目里大量使用了这类标准库装饰器,不想逐个给函数加装饰器,可以在程序入口处统一替换内置的help函数,让它在生成帮助信息前自动剥离所有装饰器包装层,直接基于原始函数生成文档:
这种方案一次配置后全局生效,不管函数加了多少层import builtins import inspect _origin_help = builtins.help def patched_help(obj, *args, **kwargs): try: # 递归解包所有装饰器,拿到最原始的被包装对象 unwrapped_obj = inspect.unwrap(obj) return _origin_help(unwrapped_obj, *args, **kwargs) except Exception: # 解包异常时回退到原始help逻辑,避免报错 return _origin_help(obj, *args, **kwargs) builtins.help = patched_helplru_cache、cached_property之类的标准库装饰器,help()输出的头部提示都会和未装饰时完全一致。
不要直接修改Python标准库的源码来解决这个问题,会破坏环境一致性,上面两种方案都不会改动标准库逻辑,也不会影响代码运行性能。
内容的提问来源于stack exchange,提问作者neves
相关产品推荐
相关产品推荐

