【问题标题】:How is this called and how can be done ( `function_name.decorator` )?这是如何调用的以及如何完成(`function_name.decorator`)?
【发布时间】:2011-08-25 23:45:28
【问题描述】:

真的很抱歉这个极其愚蠢的标题,但如果我知道它是什么,我就不会在这里写了(:

def some_decorator( func ):
    # ..

class A:
    @some_decorator
    def func():
        pass
    @func.some_decorator    # this one here - func.some_decorator ?
    def func():
        pass

some_decorator 装饰 func - 没关系。但是func.some_decorator 是什么以及some_decorator 如何成为func 的成员(或其他?)?

附:我有 90% 的把握,这里有这样的问题(因为这似乎很基本),但我不知道如何搜索它。如果有 exact 重复,我会删除这个问题。


注意:这两个成员函数都命名为func,这不是拼写错误,也不是意外。装饰器用于重载:问题与Decorating method (class methods overloading)有关

【问题讨论】:

  • 当你在寻找类似的东西时,试试dir(),就像dir(func)一样。
  • 我知道dir,这是我想到的第一件事,但我只是把它看作是一种语法,在这样的例子中,没有任何真正的实现,所以@987654332 @ 在这里不工作。还是 10 倍。
  • 你真正想做什么? (或者你想理解别人的代码?)
  • 好吧,我正在尝试为方法重载添加功能,就像在相关问题中一样,但不仅仅是使用标准语法@decorator,而是使用此处描述的语法 - 使用@decorator对于第一种方法,然后使用@first_method.decorator。我只是将其视为一种语法,并想理解并尝试实现这样的东西。这似乎有点不必要,但我只是在练习,没什么大不了的。

标签: python python-3.x decorator


【解决方案1】:

记住,带有装饰器的函数定义等价于:

def func():
    pass
func = some_decorator(func)

所以在下面几行中,func 不是指您定义的函数,而是指装饰器将其变成的函数。另请注意,装饰器可以返回 any 对象,而不仅仅是函数。所以some_decorator 返回一个带有方法的对象(不幸的是,名称some_decoratorfunc 在示例中被重用——这令人困惑,但并没有改变这个概念的任何内容),它本身就是一个装饰器。因为@ 之后的表达式首先被求值,所以在定义了另一个普通函数func 之后,您仍然可以引用第一个装饰器的方法。该装饰器应用于这个新功能。完整的例子就相当于这样:

class A:
    def func():
        pass
    func = some_decorator(func)

    _decorator = func.some_decorator
    def func():
        pass
    func = _decorator(func)

【讨论】:

  • 其实我说的是这种情况,当funca_method同名时(这是一个关于重载的情况)。所以,func被重用并不是不幸
  • @Kiril:不幸的是,它令人困惑。它并没有改变这个概念 - 唯一的区别是您在接近尾声时覆盖了第一个装饰器,但您仍然首先将第二个函数定义传递给它的方法,并以该方法调用的结果结束 func .编辑以澄清一件可能看起来自相矛盾的事情。
  • @delnan - 好的,你的最后一次编辑让我现在更清楚了。但这不适用于 any 装饰器,对吧? (或者至少,我无法让它工作)。看看这个_decorator = func.some_decorator - 这意味着装饰器不应该返回一个函数,而是一些对象,对吧?
  • @Kiril:正确 - 显然,这不适用于所有装饰器,就像 sum(x.n for x in xs) 不适用于所有可迭代对象 xs
  • @delnan - 好的,我明白了。对于愚蠢的问题,我很抱歉,但我是一个完全的 Python 初学者。 10x
【解决方案2】:

澄清这一点的一种方法是用一个行为类似这样的具体示例来演示它,builtin property descriptor

class C(object):
    @property
    def x(self):
        "This is a property object, not a function"
        return self._x
    @x.setter
    def x(self, val):
        self._x = val

>>> c = C()
>>> c.x = 1
>>> c.x
1
>>> C.x
<property object at 0x2396100>
>>> C.x.__doc__
'This is a property object, not a function'
>>> C.x.getter.__doc__
'Descriptor to change the getter on a property.'
>>> C.x.setter.__doc__ 
'Descriptor to change the setter on a property.'
>>> C.x.deleter.__doc__
'Descriptor to change the deleter on a property.'

第一次调用property(作为装饰器)意味着x 不是一个函数——它是一个属性描述符。属性的一个特点是,它们允许您最初只定义 fget 方法,然后通过使用 property.setterproperty.deleter 装饰器提供 fsetfdel(尽管因为它们中的每一个都创建了一个 new 属性对象,您确实需要确保每次使用相同的名称)。

每当您看到使用这种模式的代码时,通常都会出现类似的情况。理想情况下,所涉及的装饰器的命名将使所发生的事情相当清楚(例如,大多数人似乎很容易掌握定义property 属性的习惯用法)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-11-16
    • 2021-06-07
    • 1970-01-01
    • 2011-02-22
    • 1970-01-01
    • 1970-01-01
    • 2020-09-17
    • 1970-01-01
    相关资源
    最近更新 更多