为什么有必要将self作为方法装饰器的参数?

时间:2017-08-08 13:45:00

标签: python decorator python-decorators

对于模块级函数,此代码包含:

def dec(f):
    def wrap(*args, **kwargs):
        f(*args, **kwargs)
    return wrap

@dec
def foo(arg1):
    pass

然而,当装饰方法时,你必须有一个参数来捕捉实例。

def dec(f):
    def wrap(self, *args, **kwargs):
        f(self, *args, **kwargs)
    return wrap


class Test:
    def __init__(self):
        pass

    @dec
    def foo(self, arg1):
        pass

为什么会这样?关于self *args无法捕捉它的特别之处是什么?毕竟不仅仅是另一个位置论证? 另外,它是如何(self)传递到内部wrap函数的?

对于第一种情况,它只相当于foo = dec(foo)。从我通过闭包学到的知识,在foo作为参数传递给装饰器之前。它创建了一个__closure__的机箱,因此它可以保留传递给foo的任何参数。

为什么当谈到方法时,显然self似乎不是__closure__的一部分?

2 个答案:

答案 0 :(得分:3)

  

为什么会这样? self *args无法捕捉到它的特别之处是什么?

这个问题是基于一个有缺陷的前提。事实上,*args可以包括self,无论是否有装饰器。以下两个例子说明了这一点。

没有装饰者:

class Test(object):

  def foo(self, *args):
    return (self,) + args

  def bar(*args):  # for the purposes of illustration
    return args

t = Test()
print(t.foo(42))
print(t.bar(42))

有装饰者:

def dec(f):
    def wrap(*args, **kwargs):
        return f(*args, **kwargs)
    return wrap

class Test(object):

    @dec
    def foo(self, arg1):
        return (self, arg1)

t = Test()
print(t.foo(42))

答案 1 :(得分:0)

我认为Python本身的创造者最好说明了这一点:

http://neopythonic.blogspot.com/2008/10/why-explicit-self-has-to-stay.html

主要两点是:

  

有一个很好的论据要求在参数列表中要求明确的“自我”强化了这两种调用方法的方法之间的理论等效性。

  

在参数列表中保持显式“self”的另一个论点是能够通过将函数戳入其中来动态修改类,从而创建相应的方法。