装饰Python类方法-如何将实例传递给装饰器?

装饰Python类方法-如何将实例传递给装饰器?,python,python-decorators,Python,Python Decorators,这是Python2.5,它也是,并不重要 我有以下代码。我在bar中装饰foo()方法,使用dec_check类作为装饰器 class dec_check(object): def __init__(self, f): self.func = f def __call__(self): print 'In dec_check.__init__()' self.func() class bar(object): @dec_check def foo(

这是Python2.5,它也是,并不重要

我有以下代码。我在bar中装饰foo()方法,使用dec_check类作为装饰器

class dec_check(object):

  def __init__(self, f):
    self.func = f

  def __call__(self):
    print 'In dec_check.__init__()'
    self.func()

class bar(object):

  @dec_check
  def foo(self):
    print 'In bar.foo()'

b = bar()
b.foo()
执行此操作时,我希望看到:

In dec_check.__init__()
In bar.foo()
但是我得到了“
TypeError:foo()只接受一个参数(给定0)
”,因为
。foo()
,作为一个对象方法,将self作为一个参数。我猜问题是当我执行装饰器代码时,
bar
的实例实际上并不存在


那么如何将
bar
的实例传递给decorator类呢?

您需要通过确保其(元)类具有
\uuuu get\uuuu
方法,或者通过使用decorator函数而不是decorator类(因为函数已经是描述符),使decorator成为一个--实例。例如:

这张照片

In deco
in bar.foo

根据需要。

当函数足够时,Alex的答案就足够了。但是,当您需要一个类时,您可以通过向decorator类添加以下方法使其工作

def __get__(self, obj, objtype):
    """Support instance methods."""
    import functools
    return functools.partial(self.__call__, obj)
要理解这一点,您需要了解描述符协议。描述符协议是将事物绑定到实例的机制。它由
\uuuu get\uuuuu
\uuu set\uuuu
\uuu delete\uuuuuu
组成,当从实例字典中获取、设置或删除对象时调用


在这种情况下,当从实例中获取对象时,我们将使用partial将其
\uuuuu call\uuuu
方法的第一个参数绑定到实例。构建类时,成员函数会自动执行此操作,但对于这样的合成成员函数,我们需要显式执行此操作。

如果要将装饰器作为类编写,可以执行以下操作:

from functools import update_wrapper, partial

class MyDecorator(object):
    def __init__(self, func):
        update_wrapper(self, func)
        self.func = func

    def __get__(self, obj, objtype):
        """Support instance methods."""
        return partial(self.__call__, obj)

    def __call__(self, obj, *args, **kwargs):
        print('Logic here')
        return self.func(obj, *args, **kwargs)

my_decorator = MyDecorator

class MyClass(object):
     @my_decorator
     def my_method(self):
         pass

@Gilbert描述符协议是将事物绑定到实例的机制。它由uuuuuu获取uuuu、设置uuuuu和删除uuuuuuuuu组成,在从实例字典中获取、设置或删除对象时调用。在这种情况下,当从实例中获取对象时,我们使用partial将它的_; call _;方法的第一个参数绑定到实例。构造类时,成员函数会自动执行此操作,但是对于像这样的合成成员函数,我们需要显式地执行它。那么如果装饰器接受参数呢?python文档有一节更详细的代码说明:实现
\uuuu get\uuuu
的更好方法是使用
类型.MethodType
来创建实际的绑定(或者在某些情况下在Py2上,unbound)方法对象。在Py2上,您将使
\uuuu get\uuu
主体
返回类型.MethodType(self、instance、instancetype)
;在Py3上,首先在
实例上测试
None
,以避免绑定(
如果实例为None:returnself
),否则,将
返回types.MethodType(self,instance)
。完整的例子。将
导入
放在
获取
之外<代码>导入(甚至缓存)对于简单的属性查找来说是相对昂贵的。将
f(self)
行更改为
return f(self)
以将
foo
的返回传递回调用方。到描述符页的链接断开。@Apteryx:I linked;干,但覆盖得足够好。如何使用此实现将一些参数传递给装饰器?如何将参数传递给此装饰器?我尝试向
\uuuu init\uuuu
方法添加额外的参数,但是当实例化装饰器时,我真的不知道要为
func
传递什么:
@my\u装饰器(func,given\u arg)
@mhyousefi你能找到这个问题的答案吗?@Ferus老实说,我不记得了。)如果我这样做,我会更新它。@mhyousefi没问题,我实际上想出了一个解决方案,在构造函数中添加了
self.func=decorator()(self.func)
,而不是添加了一个decorator。
from functools import update_wrapper, partial

class MyDecorator(object):
    def __init__(self, func):
        update_wrapper(self, func)
        self.func = func

    def __get__(self, obj, objtype):
        """Support instance methods."""
        return partial(self.__call__, obj)

    def __call__(self, obj, *args, **kwargs):
        print('Logic here')
        return self.func(obj, *args, **kwargs)

my_decorator = MyDecorator

class MyClass(object):
     @my_decorator
     def my_method(self):
         pass