37

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

下面的代码是在网上找到的一些东西的片段。我感兴趣的关键是@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
4

6 回答 6

41

好好看看这个巨大答案/小说。这是我遇到的最好的解释之一。

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

这段代码,例如:

@decorate
def foo(a):
  print a

如果您删除装饰器语法,则相当于此代码:

def bar(a):
  print a

foo = decorate(bar)

装饰器有时接受参数,这些参数被传递给动态生成的函数来改变它们的输出。

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

于 2012-08-21T00:26:06.567 回答
16

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

我们使用@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))
# 5    
print(add.data)
# 3
于 2017-09-29T07:01:33.123 回答
8

装饰器语法:

@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
于 2012-08-21T00:56:42.507 回答
6

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

让我们说,您的原始函数称为 orig_func()。

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

orig_func()            #calling 

运行这个文件, orig_func() 被调用并打印。“呼”。

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

所以,我们可以这样做,通过选项 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 的代码,这就是装饰器的目的。

于 2017-12-03T07:15:18.967 回答
1

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

简单示例:

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())
于 2019-09-04T11:34:38.513 回答
0

我将使用代码来响应此问题。

我需要什么?:我需要修改math.sin()的定义以始终将 1 添加到值的正弦上

问题:我没有 math.sin() 代码

解决方案:装饰器

import math

def decorator_function(sin_function_to_modify):
    def sin_function_modified(value):
        # You can do something BEFORE math.sin() == sin_function_to_modify call
        value_from_sin_function = sin_function_to_modify(value)
        # You can do something AFTER math.sin() == sin_function_to_modify call
        new_value = value_from_sin_function + 1;
        return new_value;

    return sin_function_modified

math.sin = decorator_function(math.sin);

print(math.sin(90))

在实现装饰器之前返回 math.sin(90): 0.8939966636005579

实现装饰器后返回 math.sin(90): 1.8939966636005579

于 2021-08-29T02:19:49.627 回答