Functools.update_wrapper() 无法正常工作

Posted

技术标签:

【中文标题】Functools.update_wrapper() 无法正常工作【英文标题】:Functools.update_wrapper() doesn't work properly 【发布时间】:2014-11-16 09:03:45 【问题描述】:

我在装饰器中使用了Functools.update_wrapper(),但似乎update_wrapper 只重写了函数属性(例如__doc____name__),但不影响help() 函数。

我知道these answers,但它们不适用于装饰器类。

这是我的功能。

import functools

class memoized(object):

    def __init__(self, func):
        self.func = func
        functools.update_wrapper(self, func)

    def __call__(self, *args):
        self.func(*args)

@memoized 
def printer(arg):
    "This is my function"
    print arg

这是输出

>>> printer.__doc__
This is my function

>>> help(printer)
Help on memoized in module __main__ object:

printer = class memoized(__builtin__.object)
 |  Methods defined here:
 |  
 |  __call__(self, *args)
 |  
 |  __init__(self, func)
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)

它看起来像一个错误,但我该如何修复它?

【问题讨论】:

【参考方案1】:

functools.update_wrapper() 在实例上设置属性,但help() 查看关于类型的信息

所以printer.__doc__ 给你实例属性,help() 打印关于type(printer) 的信息,例如memoized 类,它没有 __doc__ 属性。

这不是错误,这完全是设计使然; help() will always look at the class when you pass in an instance。如果您希望 help() 为装饰函数工作,请不要使用类作为装饰器。

【讨论】:

那么,有没有办法修复它,只要我使用一个类作为装饰器? @user3664218:确实; help() 为您提供有关类的信息,而不是实例,如果您想要后者,则不应使用类装饰器。 @NeilG pydoc 源代码中的 cmets 很清楚:因为通常当您传入某个实例时,您通常希望记录可用的方法,而不是实例属性。那是正常的用例。 Pydoc 无法检测到该实例在此处被用作方法的替代品,这可能很不幸,但我不确定您是否会将其称为 broken 我认为它被破坏了,因为使用类是一种标准方式,而我是实现装饰器的最通用方式。他们应该考虑的一种解决方法是使用默认为 type(self) if not isinstance(self, type) else self__helpobject__ 魔术方法,这将允许实现装饰器模式的类覆盖此方法。 @NeilG:使用类来装饰并不是所有的那个标准;大多数装饰器使用函数(带有闭包)。如果我需要在对象上实现自定义绑定行为或其他方法,我只会使用一个类。装饰器是 Python 中相对较晚的补充,Pydoc 是较旧的设置。如果这个问题足够人们关心,核心开发人员可能会想出一些东西。您可以通过讨论 Python-ideas 的想法或在 bugs.python.org 上提交问题来提供帮助。

以上是关于Functools.update_wrapper() 无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章

装饰器进阶

python 通用 修饰器