【问题标题】:How do I decorate an instance method with another class in Python 2.7?如何在 Python 2.7 中用另一个类装饰实例方法?
【发布时间】:2014-05-31 20:40:45
【问题描述】:

在 Python 2.7 中,我想在类 Foo 中装饰一个实例方法 test,该装饰器也是一个名为 FooTestDecorator 的类。从用户 Chirstop 的 question 和 Python 2 文档的 Descriptor HowTo guide 我创建了这个示例。

但是似乎有一个问题,当我打印我的装饰方法对象时,它的(已检查?)名称是错误的,因为它被标记为像 Foo.? 这样的问号。

import types
class FooTestDecorator(object):
    def __init__(self,func):
        self.func=func
        self.count=0
        # tried self.func_name = func.func_name, but seemed to have no effect

    def __get__(self,obj,objtype=None):
        return types.MethodType(self,obj,objtype)
    def __call__(self,*args,**kwargs):
        self.count+=1
        return self.func(*args,**kwargs)

class Foo:
    @FooTestDecorator
    def test(self,a):
        print a
    def bar(self,b):
        print b

如果你测试它:

f=Foo()
print Foo.__dict__['test']
print Foo.test
print f.test
print Foo.__dict__['bar']
print Foo.bar
print f.bar

你得到

<__main__.FooTestDecorator ...object...>
<unbound method Foo.?>
<bound method Foo.? of ...instance...>
<function bar at 0x...>
<unbound method Foo.bar>
<bound method Foo.bar of ...instance...>

您可以看到替换方法显示为Foo.?。这似乎是错误的。

如何正确使用类修饰的实例方法?

注意:我的原因是我想使用 FooDecorator 实例的 self 中的变量,我将在 init 中设置这些变量。为了简单起见,我没有把它放在示例中。

【问题讨论】:

    标签: python class decorator python-decorators descriptor


    【解决方案1】:

    您的装饰器实例没有 __name__ 属性,因此 Python 只能使用问号。

    使用functools.update_wrapper() 复制函数名称以及一些其他有趣的特殊属性(例如文档字符串、函数模块名称和函数可能具有的任何自定义属性):

    import types
    from functools import update_wrapper
    
    class FooTestDecorator(object):
        def __init__(self,func):
            self.func=func
            self.count=0
            update_wrapper(self, func)
    
        def __get__(self,obj,objtype=None):
            return types.MethodType(self,obj,objtype)
        def __call__(self,*args,**kwargs):
            self.count+=1
            return self.func(*args,**kwargs)
    

    演示:

    >>> f=Foo()
    >>> print Foo.__dict__['test']
    <__main__.FooTestDecorator object at 0x11077e210>
    >>> print Foo.test
    <unbound method Foo.test>
    >>> print f.test
    <bound method Foo.test of <__main__.Foo instance at 0x11077a830>>
    

    【讨论】:

    • 你打字太快了。 :(
    • @kojiro 实际上,我相信他已经预先回答了关于 SO 的所有可能问题,而他没有立即回复的唯一原因是需要一段时间才能找到复制粘贴的答案.
    • @SethMMorton 真的吗?我还以为他也自动进行了搜索,而他花了这么长时间的唯一原因是 Global Interpeter Lock。
    猜你喜欢
    • 2014-12-31
    • 1970-01-01
    • 2020-10-15
    • 2021-12-26
    • 2018-11-11
    • 2019-02-03
    相关资源
    最近更新 更多