在Python中实现多个装饰器

Python最主要的特征之一是我们可以使用装饰器来改变函数或类的行为。我们可以使用装饰器,用已经在程序中的代码对程序的某个部分进行修改。

装饰器是程序中的几行代码,在执行过程中改变该程序的某些部分。在编译过程中引起程序变化的过程被称为元编程。

在这篇文章中,读者将了解装饰器的基本知识,即它是如何在Python中声明、实现和连锁的。

实现一个装饰器:作为第一类对象的函数

从语法上讲,我们可以通过将一个函数作为可迭代对象传递给另一个函数来声明装饰器。这是可能的,因为 Python 中的所有东西都是第一类对象;因此,我们可以把每个 Python 构造作为参数传递,或者把它赋值给一个变量。

这意味着每个类、函数和声明的变量都可以作为对象传递。下面的例子证明了这一点:

代码:

def func():
    def inner():
        print("Chocolate")
    return inner
taste = func()
taste()

输出:

"C:UsersWin 10main.py"
Chocolate
Process finished with exit code 0

这里创建了一个嵌套函数,其中父函数func() 有一个内部函数inner()inner() 函数打印一个语句,并在函数内部返回自己。

装饰函数func() 将其数据传递给一个空对象函数taste 。从而对其进行装饰。

如果这个对象函数有任何功能,装饰器也会对它进行修改。在本文的后半部分,你将看到装饰器是如何用于激发函数的变化的。

在 Python 中,我们可以把函数作为参数传递和返回给其它函数。一个装饰器也可以接受一个函数作为参数,并使用这个概念返回结果。

下面的例子演示了参数化的装饰器。为了更容易地理解它,把函数看作是现实世界的对象。

在Python中实现一个参数化的装饰器

我们将介绍一个面包店的例子来理解装饰器如何将其他函数作为参数化的参数。

在这里,bakery 是一个参数化的方法,它把一个对象函数obj_func() 作为参数。在这个方法内部,声明了一个嵌套函数inner() ,它打印了Dough

之后,obj_func() 被调用,返回inner() 函数。调用对象函数会调用被装饰的函数。

你可以仔细观察,bakery 是一个参数化的方法,它接收参数obj_func() ,这个参数只不过是函数wheat() ,并在inner() 函数执行print 语句后调用它。

代码:

    def inner():
        print("Dough")
        obj_func()
    return inner

这个应该被装饰的函数,即wheat ,有一个print 语句:Turned into bread

代码:

def wheat():
    print("Turned into bread")

一个新的对象函数final ,它存储了被装饰的函数。

语法object_function = decorator(decorated_function) ,通过将函数wheat() 作为对象传递给参数化方法bakery ,实现对函数inner() 的属性,从而装饰了函数 。

代码:

final = bakery(wheat)
final()

装饰后的函数被保存在对象函数final 。编译时,程序首先执行inner() 函数,然后调用obj_func() ,它传递对象函数wheat() ,并打印其内容。

宽泛地说,小麦放在面包店内就会转化为面包,并打印出结果:Turned into bread 。就像面包店在现实世界中的工作方式一样!

代码:

def bakery(obj_func):
    def inner():
        print("Dough")
        obj_func()
    return inner
def wheat():
    print("Turned into bread")
final = bakery(wheat)
final()

输出:

"C:UsersWin 10main.py"
Dough
Turned into bread
Process finished with exit code 0

在Python中使用@ 实现装饰器

这一段演示了如何使用语法@function_name 来装饰一个函数。在这个例子中,使用了一个程序,它有:

  • 一个参数化的嵌套函数;
  • 一个内部函数,它检查变量x和y之间的值,如果分子小于分母,则将它们交换;
  • 第三个函数,用交换后的数值进行装饰,将两个数字相除并打印出来。

装饰函数decor_func ,以一个对象函数obj1 为参数。在内部,创建了一个内部函数,如果在分母字段中提供了一个较大的数字,该函数就会交换数值。

代码:

def decor_func(obj1):
    def swap(x, y):

由于内部函数swap 的参数与函数quot 的参数相同,存储在obj1 内的交换值将从内部函数返回,在编译器执行之前将改变的值传递给函数quot

语法@decor_func 在本例中被声明在函数quot 的上方。它告诉编译器取走函数obj1 的参数并将其传递给函数quot

代码:

def decor_func(obj1):
    def swap(x, y):
        if x < y:
            temp = x
            x = x + y - x
            y = y + temp - y
        return obj1(x, y)
    return swap
# Syntax to Decorate function
@decor_func
def quot(x, y):    # Displays quotient of variable x/y
    print(x / y)
quot(2,4)

输出:

"C:UsersWin 10main.py"
2.0
Process finished with exit code 0

在Python中实现多个装饰器

链式装饰器是一种将装饰器堆叠在一起的技术,这样目标函数就会被重复装饰,其次数为@function_name 声明的次数。

在下面的程序中,创建了两个函数:decordecor1 。这些函数是装饰器,有一个内部函数,执行算术运算并返回结果。

为了连锁装饰器,必须在要装饰的函数上面一起定义(在彼此的上面)。还必须注意的是,编译器从下往上读取装饰器。

这意味着放在函数名上方的装饰器会首先被实现,其他的装饰器会在这之后向上方实现。

代码:

@decor # Gets implemented second
@decor1 # Gets implemented first
def num():
    return 5

在下面的例子中,函数num() 串行地返回一个值给装饰器函数。首先,decor1 接受该值,将其传递给对象函数func() ,并将改变后的值返回给num()

类似地,这个过程在其他装饰器函数中重复。最后,当num() 被打印时,它产生的输出是50

代码:

# 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
@decor
@decor1
def num():
    return 5
print(num())

输出:

"C:UsersWin 10main.py"
50
Process finished with exit code 0

结论

这篇文章为读者提供了一幅清晰的画面,即装饰器是如何在程序中使用的。读者应该学会如何将装饰器用于一个函数,如何向装饰器提供参数,以及如何将多个装饰器连锁。