代码之家  ›  专栏  ›  技术社区  ›  culebrón

在应用装饰器时如何保持帮助字符串相同?

  •  2
  • culebrón  · 技术社区  · 16 年前

    如何在应用修饰符后保持函数中的帮助字符串可见?

    现在,doc字符串(部分)被decorator内部函数的字符串替换。

    def deco(fn):
        def x(*args, **kwargs):
            return fn(*args, **kwargs)
        x.func_doc = fn.func_doc
        x.func_name = fn.func_name
        return x
    
    @deco
    def y(a, b):
        """This is Y"""
        pass
    
    def z(c, d):
        """This is Z"""
        pass
    
    help(y) # 1
    help(z) # 2
    

    在y函数中,所需参数没有显示在帮助中。用户可以假定它接受任何参数,但实际上它不接受。

    y(*args, **kwargs) <= y(a, b) is desired
        This is Y
    
    z(c, d)
        This is Z
    

    我用 help() dir() 很多,因为它比PDF手册快,而且想为我的库和工具制作可靠的文档字符串,但这是一个障碍。

    2 回复  |  直到 16 年前
        1
  •  1
  •   Alex Martelli    16 年前

    你所要求的是很难做到“正确”,因为 help 从获取函数签名 inspect.getargspec 这反过来又从内省中得到了它,内省不能被直接愚弄——正确地这样做意味着动态生成一个新的函数对象(而不是简单的包装函数),使用正确的参数名称和数字(以及默认值)。换句话说,非常困难,高级,需要黑魔法字节码破解。

    我认为通过MonkeyPatching(从来不是一个令人愉快的前景,但有时是执行定制任务的唯一方法,否则很难证明几乎是不可能的,就像您需要的那样),将real inspect.getargspec替换为您自己的lookeake函数,该函数使用look aside表(映射包装器您生成给包装函数的argspec的函数,或者委托给实际的函数)。

    import functools
    import inspect
    
    realgas = inspect.getargspec
    
    lookaside = dict()
    
    def fakegas(f):
        if f in lookaside:
            return lookaside[f]
        return realgas(f)
    
    inspect.getargspec = fakegas
    
    def deco(fn):
        @functools.wraps(fn)
        def x(*args, **kwargs):
            return fn(*args, **kwargs)
        lookaside[x] = realgas(fn)
        return x
    
    @deco
    def x(a, b=23):
      """Some doc for x."""
      return a + b
    
    help(x)
    

    按要求打印:

    Help on function x in module __main__:
    
    x(a, b=23)
        Some doc for x.
    (END)
    
        2
  •  5
  •   Autoplectic    16 年前

    给予 decorator 偷看模块。我相信它完全符合你的要求。

    In [1]: from decorator import decorator
    In [2]: @decorator
       ...: def say_hello(f, *args, **kwargs):
       ...:     print "Hello!"
       ...:     return f(*args, **kwargs)
       ...: 
    In [3]: @say_hello
       ...: def double(x):
       ...:     return 2*x
       ...: 
    

    信息上写着“双(X)”。

    推荐文章