在Python中,函数上方带“@”的装饰器是什么?[duplicate]

tquggr8v  于 2022-11-26  发布在  Python
关注(0)|答案(7)|浏览(136)

此问题在此处已有答案

How do I make function decorators and chain them together?(19个答案)
13天前关闭。
机构群体在13天前审核了是否重新讨论此问题,并将其关闭:
原始关闭原因未解决
抱歉,这是一个非常宽泛的问题。
下面的代码是从网络上找到的一段代码。我感兴趣的是以@protected开头的代码行--我想知道这是做什么的,它是如何做的?它似乎是在执行do_upload_ AJAX 函数之前检查一个有效的用户是否登录。这看起来是一个非常有效的用户身份验证方法。但我不明白这个@函数的机制--有人能给我一个正确的方向来解释这在真实的世界中是如何实现的吗?2 Python3请回答。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
j91ykkif

j91ykkif1#

仔细看看这个enormous answer/novel,这是我遇到的最好的解释之一。
我能给予的最简短的解释是装饰器将您的函数 Package 在另一个返回函数的函数中。
例如,以下代码:

@decorate
def foo(a):
  print a

如果您移除装饰器语法,将与以下代码等效:

def bar(a):
  print a

foo = decorate(bar)

装饰器有时会接受参数,这些参数被传递给动态生成的函数以改变它们的输出。
另一个你应该仔细阅读的术语是闭包,因为这是允许装饰器工作的概念。

ru9i0ody

ru9i0ody2#

装饰器是一个函数,它把一个函数作为它唯一的参数,并返回一个函数。这有助于用相同的代码一次又一次地“ Package ”功能。
我们使用@ unc_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"

装饰器还可以用于向函数附加数据(或添加属性)。

  • 将数据附加到函数的装饰器函数 *
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
yrefmtwq

yrefmtwq3#

装饰器语法:

@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
aij0ehis

aij0ehis4#

装饰器是一个函数,它接受另一个函数,并扩展后一个函数的行为,而不显式地修改它。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的时候,我们可以在调用函数之前和之后做一些事情,这就是我们要做的。

  • ------选项二-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
def orig_func():
    print "do something before"
    print("Whee!")
    print "do something after"

orig_func()

我们已经达到了我们的目的。但是代价是什么呢?我们不得不修改orig_func的代码。这可能并不总是可能的,特别是当其他人写了这个函数的时候。但是我们希望当这个函数被调用的时候,它被以这样一种方式修改,即在之前和/或之后可以做一些事情。然后装饰器帮助我们做这件事。我们创建了一个装饰器,并且可以保持和以前一样的名字。这样,如果我们的函数被调用,它就被透明地修改了。我们经历了以下步骤。a.定义装饰器。在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

===============================================================
注意,现在orig_unc已经通过装饰器修改过了,所以,现在当你调用orig_unc()时,它将运行my_wrapper,它将执行三个步骤,正如已经概述的。
因此,您已经修改了orig_func的功能,而没有修改orig_func的代码,这是装饰器的目的。

hjzp0vay

hjzp0vay5#

Decorator只是一个将另一个函数作为参数的函数
简单示例:

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())
up9lanfz

up9lanfz6#

我要用一个代码来回应这个问题。

我需要什么?:我需要修改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

6l7fqoea

6l7fqoea7#

装饰器是一个函数,它将另一个函数作为参数来更改其结果或给予其某种效果。

例如,用下面的代码:

# 4 + 6 = 10

def sum(num1, num2):
    return num1 + num2

result = sum(4, 6)
print(result)

我们可以得到下面的结果:

10

接下来,我们创建minus_2(),从sum()的结果中减去2,如下所示:

# (4 + 6) - 2 = 8

def minus_2(func): # Here
    def core(*args, **kwargs):
        result = func(*args, **kwargs)
        return result - 2
    return core

def sum(num1, num2):
    return num1 + num2
    
f1 = minus_2(sum)
result = f1(4, 6)
print(result)

简而言之:

# ...

result = minus_2(sum)(4, 6)
print(result)

然后,我们可以得到下面的结果:

8

现在,我们可以使用minus_2()作为带有sum()的装饰器,如下所示:

# (4 + 6) - 2 = 8

def minus_2(func):
    def core(*args, **kwargs):
        result = func(*args, **kwargs)
        return result - 2
    return core

@minus_2 # Here
def sum(num1, num2):
    return num1 + num2
    
result = sum(4, 6)
print(result)

然后,我们可以得到下面同样的结果:

8

接下来,我们创建times_10(),将minus_2()的结果乘以10,如下所示:

# ((4 + 6) - 2) x 10 = 80

def minus_2(func):
    def core(*args, **kwargs):
        result = func(*args, **kwargs)
        return result - 2
    return core

def times_10(func): # Here
    def core(*args, **kwargs):
        result = func(*args, **kwargs)
        return result * 10
    return core

def sum(num1, num2):
    return num1 + num2

f1 = minus_2(sum)
f2 = times_10(f1)
result = f2(4, 6)
print(result)

简而言之:

# ...

result = times_10(minus_2(sum))(4, 6)
print(result)

然后,我们可以得到下面的结果:

80

现在,我们可以使用times_10()作为装饰器,sum()位于@minus_2之上,如下所示:

# ((4 + 6) - 2) x 10 = 80

def minus_2(func):
    def core(*args, **kwargs):
        result = func(*args, **kwargs)
        return result - 2
    return core

def times_10(func):
    def core(*args, **kwargs):
        result = func(*args, **kwargs)
        return result * 10
    return core

@times_10 # Here
@minus_2
def sum(num1, num2):
    return num1 + num2

result = sum(4, 6)
print(result)

然后,我们可以得到下面同样的结果:

80

不要忘记,如果一个函数有多个如上所述的装饰器,它们将按照如下所示从下至上的顺序执行:

# ((4 + 6) - 2) x 10 = 80

@times_10 # 2nd executed.
@minus_2  # 1st executed. 
def sum(num1, num2):
    return num1 + num2

然后,我们可以得到与上面示例中相同的结果:

80

所以,如果我们改变它们的顺序如下所示:

# ((4 + 6) * 10) - 2 = 98

@minus_2  # 2nd executed.
@times_10 # 1st executed. 
def sum(num1, num2):
    return num1 + num2

然后,我们可以得到下面不同的结果:

98

最后,我们在Django中创建了下面的代码,通过@tran在事务中运行test()

# "views.py"

from django.db import transaction
from django.http import HttpResponse

def tran(func): # Here
    def core(request, *args, **kwargs):
        with transaction.atomic():
            return func(request, *args, **kwargs)
    return core

@tran # Here
def test(request):
    person = Person.objects.all()
    print(person)
    return HttpResponse("Test")

相关问题