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

Why is it necessary to place self as a parameter for method 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__

我觉得Python的作者本人说得最好:

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

主要有两点:

There's a pretty good argument to make that requiring explicit 'self' in the parameter list reinforces the theoretical equivalency between these two ways of calling a method.

Another argument for keeping explicit 'self' in the parameter list is the ability to dynamically modify a class by poking a function into it, which creates a corresponding method.

Why is that the case? What's so special about self that *args isn't able to catch it?

这个问题基于一个有缺陷的前提。事实上,*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))