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

Duk*_*gal 17 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
Run Code Online (Sandbox Code Playgroud)

Ble*_*der 27

以一个良好的看看这个巨大的接听/小说.这是我遇到过的最好的解释之一.

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

这段代码,例如:

@decorate
def foo(a):
  print a
Run Code Online (Sandbox Code Playgroud)

如果删除装饰器语法,则等效于此代码:

def bar(a):
  print a

foo = decorate(bar)
Run Code Online (Sandbox Code Playgroud)

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

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

  • 很好的答案,我的意思是你的。不是小说。 (2认同)

Tus*_*CSD 10

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

我们使用@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"
Run Code Online (Sandbox Code Playgroud)

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

装饰器功能,可将数据附加到func

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

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

print(add(2, 3))
# 5    
print(add.data)
# 3
Run Code Online (Sandbox Code Playgroud)


jfs*_*jfs 7

装饰器语法:

@protected(check_valid_user) 
def do_upload_ajax():
    "..."
Run Code Online (Sandbox Code Playgroud)

相当于

def do_upload_ajax():
    "..."
do_upload_ajax = protected(check_valid_user)(do_upload_ajax)
Run Code Online (Sandbox Code Playgroud)

但不需要重复三次同名.没有更多的东西.

例如,这里有一个可能的实现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
Run Code Online (Sandbox Code Playgroud)


小智 6

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

假设您的原始函数称为orig_func()。

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

orig_func()            #calling 
Run Code Online (Sandbox Code Playgroud)

运行该文件,orig_func()被调用并打印。“呜”。

现在,让我们说,我们要修改此函数,以在调用此函数之前执行某些操作,并在此函数之后执行某些操作。

因此,我们可以通过选项1或选项2来做到这一点

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

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

print "do something before"
orig_func()
print "do something after"
Run Code Online (Sandbox Code Playgroud)

请注意,我们尚未修改orig_func。相反,我们在此功能之外进行了更改。但是可能是,我们希望以一种方式进行更改,使得在调用orig_func时,我们能够在调用该函数之前和之后执行某些操作。所以,这就是我们要做的。

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

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

orig_func()
Run Code Online (Sandbox Code Playgroud)

我们已经达到了目的。但是要花多少钱呢?我们必须修改orig_func的代码。特别是当其他人编写了该功能时,这可能并不总是可能的。但是我们希望在调用此函数时以某种方式进行修改,以便可以执行之前和/或之后的操作。然后,装饰器将帮助我们完成此任务,而无需修改orig_func的代码。我们创建一个装饰器,并且可以保持与以前相同的名称。因此,如果我们的函数被调用,它将被透明地修改。我们执行以下步骤。一种。定义装饰器。在docorator中,1)如果需要,在orig_func之前编写代码以执行某些操作。2)调用orig_func,以完成其工作。3)如果愿意,可以在orig_func之后编写代码以执行某些操作。b。创建装饰器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
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 你能在最后一个代码块后面添加几行,以展示它使用“@”和装饰器语法的样子吗? (2认同)

Ash*_*and 5

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

需要装饰器:我们想使用 Python 内置库的功能,它可以执行我们想要的任务。

问题:但问题是我们不想要精确的函数输出。我们想要定制的输出。诀窍是我们无法更改函数的原始代码。这里装饰器来帮助我们。

解决方案:Decorator 将我们需要的函数作为输入,将它包装在一个包装函数中并做 3 件事:

  1. 之前做点什么。
  2. 然后调用所需的函数()。
  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()   
Run Code Online (Sandbox Code Playgroud)