Python装饰器? - 有人可以解释一下吗?

时间:2012-08-21 00:10:56

标签: python python-3.x

道歉这是一个非常广泛的问题。

以下代码是网络上发现的内容的片段。我感兴趣的关键是从@protected开始的行 - 我想知道这是做什么以及它是如何做到的?它似乎是在执行do_upload_ajax函数之前检查有效用户是否已登录。这看起来像是一种非常有效的用户身份验证方式。我不明白这个@函数的机制 - 有人能引导我朝正确的方向解释如何在现实世界中实现它吗? Python 3请回答。感谢。

@bottle.route('/ajaxupload', method='POST')
@protected(check_valid_user) 
def do_upload_ajax():
    data = bottle.request.files.get('data')
    if data.file:
        size = 0

6 个答案:

答案 0 :(得分:23)

查看此enormous answer/novel。这是我遇到过的最好的解释之一。

我能给出的最简单的解释是装饰器将你的函数包装在另一个返回函数的函数中。

此代码,例如:

@decorate
def foo(a):
  print a
如果删除装饰器语法,

将等同于此代码:

def bar(a):
  print a

foo = decorate(bar)

装饰器有时会获取参数,这些参数会传递给动态生成的函数以改变其输出。

您应该阅读的另一个术语是闭包,因为这是允许装饰器工作的概念。

答案 1 :(得分:7)

装饰器语法:

@protected(check_valid_user) 
def do_upload_ajax():
    "..."

相当于

def do_upload_ajax():
    "..."
do_upload_ajax = protected(check_valid_user)(do_upload_ajax)

但无需重复三次相同的名称。没有更多的东西。

例如,这是protected()

的可能实现
import functools

def protected(check):
    def decorator(func): # it is called with a function to be decorated
        @functools.wraps(func) # preserve original name, docstring, etc
        def wrapper(*args, **kwargs):
            check(bottle.request) # raise an exception if the check fails
            return func(*args, **kwargs) # call the original function
        return wrapper # this will be assigned to the decorated name
    return decorator

答案 2 :(得分:6)

装饰器是一个函数,它将函数作为唯一参数并返回一个函数。这有助于一遍又一遍地使用相同的代码“包装”功能。

我们使用@func_name指定要在另一个函数上应用的装饰器。

以下示例向fun()返回的字符串添加欢迎消息。将fun()作为参数并返回welcome()。

def decorate_message(fun):

    # Nested function
    def addWelcome(site_name):
        return "Welcome to " + fun(site_name)

    # Decorator returns a function
    return addWelcome

@decorate_message
def site(site_name):
    return site_name;

print site("StackOverflow")

Out[0]: "Welcome to StackOverflow"

装饰器也可用于将数据(或添加属性)附加到函数。

用于将数据附加到func的装饰器函数

def attach_data(func):
       func.data = 3
       return func

@attach_data
def add (x, y):
       return x + y

print(add(2, 3))     
print(add.data)

答案 3 :(得分:4)

装饰器是一个函数,它接受另一个函数并扩展后一个函数的行为而不显式修改它。 Python允许“嵌套”函数,即(另一个函数中的函数)。 Python还允许您从其他函数返回函数。

让我们说,你的原始函数叫做orig_func()。

def orig_func():       #definition 
    print("Wheee!")

orig_func()            #calling 

运行此文件,调用orig_func()并打印。 “wheee”。

现在,让我们说,我们想修改这个函数,在调用这个函数之前做一些事情,也可以在这个函数之后做一些事情。

因此,我们可以通过选项1或选项2

这样做

--------选项1 ----------

def orig_func():
    print("Wheee!")

print "do something before"
orig_func()
print "do something after"

请注意,我们尚未修改orig_func。相反,我们在此功能之外进行了更改。 但也许,我们希望以这样的方式进行更改:当调用orig_func时,我们可以在调用函数之前和之后执行某些操作。所以,这就是我们的工作。

--------选项2 ----------

def orig_func():
    print "do something before"
    print("Whee!")
    print "do something after"

orig_func()

我们已达到目的。但是以什么代价?我们必须修改orig_func的代码。这可能并非总是可能,特别是当其他人编写了该功能时。然而,我们希望在调用此函数时,以这样的方式修改它,即可以在之前和/或之后完成某些操作。然后装饰器帮助我们这样做,而无需修改orig_func的代码。我们创建一个装饰器,可以保持与以前相同的名称。因此,如果调用我们的函数,它将被透明地修改。我们将执行以下步骤。 一个。定义装饰器。在docorator中,    1)如果你愿意,可以在orig_func之前编写代码来做某事。    2)调用orig_func,完成它的工作。    3)如果你愿意,可以在orig_func之后编写代码来做某事。 湾创建装饰器 C。打电话给装饰师。

我们是这样做的。

=============================================== ==============

#-------- orig_func already given ----------
def orig_func():
   print("Wheee!")

#------ write decorator ------------
def my_decorator(some_function):
    def my_wrapper():
        print "do something before"   #do something before, if you want to
        some_function()
        print "do something after"    #do something after, if you want to
    return my_wrapper

#------ create decorator and call orig func --------
orig_func = my_decorator(orig_func)   #create decorator, modify functioning 
orig_func()                           #call modified orig_func

=============================================== ================

注意,现在已经通过装饰器修改了orig_func。所以,现在当你调用orig_func()时,它将运行my_wrapper,它将执行三个步骤,如前所述。

因此你修改了orig_func的功能,而没有修改orig_func的代码,这就是装饰者的目的。

答案 4 :(得分:1)

首先,我们需要了解为什么需要装饰器。

装饰需求: 我们想使用Python内置库的功能来执行我们想要的任务。

问题: 但是问题是我们不希望确切的函数输出。我们想要定制的输出。 诀窍是我们无法更改函数的原始代码。装饰者来了。

解决方案: 装饰器将我们所需的函数作为输入,将其包装在包装函数中,然后 做三件事:

  1. 先做点事。
  2. 然后调用所需的function()。
  3. 做些事。

总代码:

def my_decorator(desired_function):
    def my_wrapper():
        print "do something before"   #do something before, if you want to
        desired_function()
        print "do something after"    #do something after, if you want to
    return my_wrapper

desired_func = my_decorator(desired_func())   #create decorator
desired_func()                           #calling desired_func()   

答案 5 :(得分:0)

装饰器只是一个将另一个函数作为参数的函数

简单示例:

def get_function_name_dec(func):
  def wrapper(*arg):
      function_returns = func(*arg)  # What our function returns
      return func.__name__ + ": " + function_returns

  return wrapper

@get_function_name_dec
def hello_world():
    return "Hi"

print(hello_world())