【问题标题】:Python decoratorsPython 装饰器
【发布时间】:2013-08-07 12:47:35
【问题描述】:

我有一个关于装饰器的问题。我了解什么是装饰器并且我知道如何使用它,我已经阅读了所有教程How to make a chain of function decorators?

我明白了:

>>> def my_decorator(fn):
>>>     print 'Do something before'
>>>     print fn()


>>> def foo():
>>>     return 'Hello World!'

>>> foo = my_decorator(foo)

那是一样的:

>>> def my_decorator(fn):
>>>     print 'Do something before'
>>>     print fn()

>>> @my_decorator
>>> def foo():
>>>     return 'Hello World!'

我知道什么是闭包以及为什么我们在带参数的装饰器中使用闭包(在嵌套函数中获取装饰器参数),但我不明白为什么我们使用闭包和嵌套函数来获取参数和函数。

闭包(或其他东西)如何访问外部参数和函数。如果没有@decorator,我将无法做同样的事情。

例如,我可以访问我的 foo() 和函数的参数,而无需在参数中传递此函数:

def my_decorator(str):
    def wrapper(fn):
        def inner_function(*args):
            print 'Do something before'
            return fn(*args)
        return inner_function
    return wrapper

@my_decorator('test')
def foo(a, b):
    return a + b


print foo(1, 1)

这怎么可能?

【问题讨论】:

  • 因为这就是装饰器所做的。这不是一个简单的函数调用,它是一个装饰器,它通过它下面的函数作为第一个参数(并且返回的函数替换它)。
  • 这并不完全是魔法——这就像问为什么函数后面的括号会调用它——它是语言的文档化部分。
  • “没有@decorator,我无法做同样的事情”是什么意思?请举个例子。
  • 和第一个例子一样,我可以看到什么是装饰器
  • 您可以使用foo = my_decorator('test')(foo),作为@ 语法的替代。

标签: python closures decorator


【解决方案1】:

装饰器是一个接受一个参数的函数(这个参数是函数)——这是我对装饰器的定义。在您的情况下,wrapper 是装饰者。而my_decorator 用于收集inner_function 的参数。 inner_function 用于替换原来的[未装饰]功能。一步一步的解释是:

  1. 调用my_decorator 来收集inner_function 的选项
  2. my_decorator 返回wrapper
  3. wrapper 负责捕获原始功能或装饰它。在您的情况下,原始功能是 foo
  4. wrapper 返回原始替换函数(即inner_function
  5. 现在foo指向inner_function,因此inner_function被执行然后foo被调用

希望它能让事情更清楚一点。

【讨论】:

  • 感谢您的评论帮助我找到了装饰器如何调用所有函数
【解决方案2】:

我找到了解决方案:

实际上装饰器使用闭包功能: 所以这里是不带装饰器和带参数做同样事情的解决方案(只是为了理解操作,学习)

def wrapper(str):
    def decorator_factory(fn):
        def inner_function(*args):
            print 'Do something before'
            return fn(*args)
        return inner_function
    return decorator_factory

@my_decorator('test')
def foo(a, b):
    return a + b

# with decorator
print foo(1, 1)

# without decorator
print wrapper('str')(foo)(1, 1)

【讨论】:

  • 另一种看待它的方式是:the_actual_decorator = my_decorator('some_string')。你看,函数my_decorator() 的命名有点糟糕(对于这个例子),因为它本身并不是一个装饰器,而是一个返回带有闭包的装饰器的包装器。这个 returned 装饰器是应用于 foo() 的装饰器。
  • 所以我必须在 wrapper() 中命名 my_decorator() ?
猜你喜欢
  • 1970-01-01
  • 2014-01-23
  • 1970-01-01
  • 2021-05-20
  • 2020-02-10
  • 2011-11-04
  • 2011-04-28
  • 1970-01-01
相关资源
最近更新 更多