📜  Python中的装饰器

📅  最后修改于: 2022-05-13 01:55:19.381000             🧑  作者: Mango

Python中的装饰器

装饰器是Python中一个非常强大和有用的工具,因为它允许程序员修改函数或类的行为。装饰器允许我们包装另一个函数以扩展被包装函数的行为,而无需永久修改它。但在深入研究装饰器之前,让我们了解一些在学习装饰器时会派上用场的概念。

头等舱物品
在Python中,函数是第一类对象,这意味着Python中的函数可以作为参数使用或传递。
一等函数的性质:

  • 函数是 Object 类型的实例。
  • 您可以将函数存储在变量中。
  • 您可以将函数作为参数传递给另一个函数。
  • 您可以从函数。
  • 您可以将它们存储在数据结构中,例如哈希表、列表……

请考虑以下示例以更好地理解。

示例 1:将函数视为对象。

Python3
# Python program to illustrate functions
# can be treated as objects
def shout(text):
    return text.upper()
 
print(shout('Hello'))
 
yell = shout
 
print(yell('Hello'))


Python3
# Python program to illustrate functions
# can be passed as arguments to other functions
def shout(text):
    return text.upper()
 
def whisper(text):
    return text.lower()
 
def greet(func):
    # storing the function in a variable
    greeting = func("""Hi, I am created by a function passed as an argument.""")
    print (greeting)
 
greet(shout)
greet(whisper)


Python3
# Python program to illustrate functions
# Functions can return another function
 
def create_adder(x):
    def adder(y):
        return x+y
 
    return adder
 
add_15 = create_adder(15)
 
print(add_15(10))


Python3
# defining a decorator
def hello_decorator(func):
 
    # inner1 is a Wrapper function in
    # which the argument is called
     
    # inner function can access the outer local
    # functions like in this case "func"
    def inner1():
        print("Hello, this is before function execution")
 
        # calling the actual function now
        # inside the wrapper function.
        func()
 
        print("This is after function execution")
         
    return inner1
 
 
# defining a function, to be called inside wrapper
def function_to_be_used():
    print("This is inside the function !!")
 
 
# passing 'function_to_be_used' inside the
# decorator to control its behaviour
function_to_be_used = hello_decorator(function_to_be_used)
 
 
# calling the function
function_to_be_used()


Python3
# importing libraries
import time
import math
 
# decorator to calculate duration
# taken by any function.
def calculate_time(func):
     
    # added arguments inside the inner1,
    # if function takes any arguments,
    # can be added like this.
    def inner1(*args, **kwargs):
 
        # storing time before function execution
        begin = time.time()
         
        func(*args, **kwargs)
 
        # storing time after function execution
        end = time.time()
        print("Total time taken in : ", func.__name__, end - begin)
 
    return inner1
 
 
 
# this can be added to any function present,
# in this case to calculate a factorial
@calculate_time
def factorial(num):
 
    # sleep 2 seconds because it takes very less time
    # so that you can see the actual difference
    time.sleep(2)
    print(math.factorial(num))
 
# calling the function.
factorial(10)


Python3
def hello_decorator(func):
    def inner1(*args, **kwargs):
         
        print("before Execution")
         
        # getting the returned value
        returned_value = func(*args, **kwargs)
        print("after Execution")
         
        # returning the value to the original frame
        return returned_value
         
    return inner1
 
 
# adding decorator to the function
@hello_decorator
def sum_two_numbers(a, b):
    print("Inside the function")
    return a + b
 
a, b = 1, 2
 
# getting the value through return of the function
print("Sum =", sum_two_numbers(a, b))


Python3
# code for testing decorator chaining
def decor1(func):
    def inner():
        x = func()
        return x * x
    return inner
 
def decor(func):
    def inner():
        x = func()
        return 2 * x
    return inner
 
@decor1
@decor
def num():
    return 10
 
print(num())


输出:

HELLO
HELLO

在上面的例子中,我们将函数shout分配给了一个变量。这不会调用该函数,而是获取由喊叫引用的函数对象并创建指向它的第二个名称,叫喊。

示例 2:将函数作为参数传递

Python3

# Python program to illustrate functions
# can be passed as arguments to other functions
def shout(text):
    return text.upper()
 
def whisper(text):
    return text.lower()
 
def greet(func):
    # storing the function in a variable
    greeting = func("""Hi, I am created by a function passed as an argument.""")
    print (greeting)
 
greet(shout)
greet(whisper)

输出:

HI, I AM CREATED BY A FUNCTION PASSED AS AN ARGUMENT.
hi, i am created by a function passed as an argument.

在上面的示例中,greet函数将另一个函数作为参数(在这种情况下是喊叫和耳语)。作为参数传递的函数然后在函数greet 中调用。

示例 3:从另一个函数。

Python3

# Python program to illustrate functions
# Functions can return another function
 
def create_adder(x):
    def adder(y):
        return x+y
 
    return adder
 
add_15 = create_adder(15)
 
print(add_15(10))

输出:

25

在上面的示例中,我们在另一个函数中创建了一个函数,然后返回了在其中创建的函数。
以上三个例子描述了理解装饰器所需的重要概念。在经历了它们之后,让我们现在深入研究装饰器。

装饰器

如上所述,装饰器用于修改函数或类的行为。在装饰器中,函数被作为参数传入另一个函数,然后在包装函数内部调用。

装饰器的语法:

@gfg_decorator
def hello_decorator():
    print("Gfg")

'''Above code is equivalent to -

def hello_decorator():
    print("Gfg")
    
hello_decorator = gfg_decorator(hello_decorator)'''

在上面的代码中,gfg_decorator 是一个可调用函数,将在另一个可调用函数hello_decorator函数之上添加一些代码并返回包装函数。

装饰器可以修改行为

Python3

# defining a decorator
def hello_decorator(func):
 
    # inner1 is a Wrapper function in
    # which the argument is called
     
    # inner function can access the outer local
    # functions like in this case "func"
    def inner1():
        print("Hello, this is before function execution")
 
        # calling the actual function now
        # inside the wrapper function.
        func()
 
        print("This is after function execution")
         
    return inner1
 
 
# defining a function, to be called inside wrapper
def function_to_be_used():
    print("This is inside the function !!")
 
 
# passing 'function_to_be_used' inside the
# decorator to control its behaviour
function_to_be_used = hello_decorator(function_to_be_used)
 
 
# calling the function
function_to_be_used()

输出:

Hello, this is before function execution
This is inside the function !!
This is after function execution

让我们看一下上面代码在调用“function_to_be_used”时是如何运行的。


让我们跳到另一个例子,我们可以使用装饰器轻松找出函数的执行时间

Python3

# importing libraries
import time
import math
 
# decorator to calculate duration
# taken by any function.
def calculate_time(func):
     
    # added arguments inside the inner1,
    # if function takes any arguments,
    # can be added like this.
    def inner1(*args, **kwargs):
 
        # storing time before function execution
        begin = time.time()
         
        func(*args, **kwargs)
 
        # storing time after function execution
        end = time.time()
        print("Total time taken in : ", func.__name__, end - begin)
 
    return inner1
 
 
 
# this can be added to any function present,
# in this case to calculate a factorial
@calculate_time
def factorial(num):
 
    # sleep 2 seconds because it takes very less time
    # so that you can see the actual difference
    time.sleep(2)
    print(math.factorial(num))
 
# calling the function.
factorial(10)

输出:

3628800
Total time taken in :  factorial 2.0061802864074707

如果一个函数返回一些东西或一个参数被传递给函数怎么办?

在上述所有示例中,函数没有返回任何内容,因此没有任何问题,但可能需要返回值。

Python3

def hello_decorator(func):
    def inner1(*args, **kwargs):
         
        print("before Execution")
         
        # getting the returned value
        returned_value = func(*args, **kwargs)
        print("after Execution")
         
        # returning the value to the original frame
        return returned_value
         
    return inner1
 
 
# adding decorator to the function
@hello_decorator
def sum_two_numbers(a, b):
    print("Inside the function")
    return a + b
 
a, b = 1, 2
 
# getting the value through return of the function
print("Sum =", sum_two_numbers(a, b))

输出:

before Execution
Inside the function
after Execution
Sum = 3

在上面的例子中,你可能会注意到内部函数的参数有很大的不同。内部函数将参数作为 *args 和 **kwargs ,这意味着可以传递任意长度的位置参数元组或关键字参数字典。这使它成为可以装饰具有任意数量参数的函数的通用装饰器。

链接装饰器

简单来说,链接装饰器意味着用多个装饰器装饰一个函数。

例子:

Python3

# code for testing decorator chaining
def decor1(func):
    def inner():
        x = func()
        return x * x
    return inner
 
def decor(func):
    def inner():
        x = func()
        return 2 * x
    return inner
 
@decor1
@decor
def num():
    return 10
 
print(num())

输出:

400

上面的示例类似于将函数调用为 -

decor1(decor(num))