【问题标题】:Why is it necessary to place self as a parameter for method decorators?为什么必须将 self 作为方法装饰器的参数?
【发布时间】:2018-01-16 03:04:06
【问题描述】:

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

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__ 的一部分?

【问题讨论】:

  • 有趣的是,如果您使用第一个示例的装饰器(因此没有在方法级别重新定义 dec(f)),那么它也可以在类内部工作,而无需调用“self”。 @dec def foo(arg1): pass 然后可以调用为 Test.foo('bar')..

标签: python decorator python-decorators


【解决方案1】:

为什么会这样? 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))

【讨论】:

    【解决方案2】:

    我认为最好由 Python 的创建者自己说:

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

    主要有两点:

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

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

    【讨论】:

    • 呃...我实际上在问一个完全不同的问题,我可能需要稍微改写一下我的问题,但这主要是关于装饰器和闭包。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-11
    • 2016-01-31
    • 2011-08-02
    • 2017-11-19
    • 2021-11-29
    • 1970-01-01
    相关资源
    最近更新 更多