Python中的装饰器入门
Python装饰器是一种设计模式,它允许开发者在不改变函数代码结构的情况下修改函数的结构。
当你想改变一个函数的行为时,这个概念很有用,所以与其进去改变整个代码,不如创建一个Python装饰器,这将允许你使用一行代码来改变所有不同函数的行为。
前提条件
理解Python编程中的一切都以对象的形式出现,是理解这个概念的关键。读者应该对Python非常熟悉,尽管对初学者的解释简单而精确。
除此之外,你还需要
- 在你的计算机上安装一个可以工作的Python。
- 一个代码编辑器,以便试用这些代码片段。
了解什么是装饰器
许多人对Python装饰器的概念并不清楚,尽管它很简单。由于这个原因,你可以把Python装饰器看作是Python中的高级函数,它把另一个函数作为参数,并把另一个函数作为返回值。
Python装饰器显示了Python编程语言是如何在你的小而有益的包中打包了若干功能。装饰器可以应用于类和函数,使编程变得更加迷人。它们可以加快性能,缩短并完全改变代码所能做的动态。
装饰器的核心支柱
由于Python中的所有东西都是一个对象,所以函数也是对象,正因为如此,它们可以被赋值给变量,而且函数可以从它们被赋值的相同变量中访问。
# the first function
def first_function():
print('The first function')
x = first_function
# calling the function from the variable
x()
输出。
The first function
其次,由于一个函数是一个对象,它可以嵌套在另一个函数中,这样当外部函数被调用时,内部函数也将被执行。
# Outter function
def umbrella_function():
# inner function
def inner_function():
print('I am the inner function')
# Executing the inner function inside the umbrela function.
inner_function()
# calling the outer function calls the inner as well
umbrella_function()
输出。
I am the inner function
第三个支柱;一个函数可以是另一个函数的返回值,因为我们可以将它们分配给变量,并嵌套在其他函数中。
def umbrella_function():
name = 'Mia Roberts'
def inner_function():
print(name)
# return a function
return inner_function
x = umbrella_function()
# calling the function via a variable
x()
输出。
Mia Roberts
接下来,一个函数可以作为一个参数传递给另一个函数,就像我们可以把变量作为参数传递一样。
# main function
def main_function(func):
func()
#parameter function
def parameter_function():
print('I am the parameter function')
# call main function passing another functions as a parameter
main_function(parameter_function)
输出。
I am the parameter function
创建 Python 装饰器
这个解释可能看起来很抽象,但如果我们举个例子,就会很容易掌握。让我们通过编写两个不同的函数来演示这些,并使用它们来探索Python装饰器的概念。
例如,如果我们把上面的函数拿出来,我们可以像下面的片段那样对它进行装饰。
def umbrella_function(function):
name = 'Mia Roberts'
def inner_function():
print(name)
function()
return inner_function
def another_function():
print('I am a computer science student')
x = umbrella_function(another_function)
x()
输出。
Mia Roberts
I am a computer science student
在上面的例子中,umbrella_function() 是一个装饰器,但是当我们说x = umbrella_function(another_function) 时,函数another_function() 被装饰了,返回的函数被分配到变量x 。
要在Python中装饰一个函数,我们在装饰函数的名字旁边使用@ 符号,并把它放在函数定义的正上方。
例如。
@umbrella_function
def another_function():
print('I am a computer science student')
上面的内容与此相同。
def another_function():
print('I am a computer science student')
x = umbrella_function(another_function)
向装饰器传递参数
有时我们可能需要定义一个接受参数的装饰器函数。我们可以通过将参数传递给包装器函数来实现,然后将其传递给被装饰的函数。
def umbrella_function(function):
def inner_function(args1, args2):
print("Arguments passed are: {0}, {1}".format(args1,args2))
function(args1, args2)
return inner_function
@umbrella_function
def another_function(name, age):
print ('So, {name} is {age} years old and she is a {occupation}'
.format(name = name, age = age, occupation = 'programmer'))
another_function('Mia', 18)
输出。
Arguments passed are: Mia, 18
So, Mia is 18 years old, and she is a programmer
调试 Python 装饰器
正如所观察到的,装饰器包裹着函数。原始函数和它的参数都被包装器所掩盖。这个问题给调试带来了挑战,要求必须解决这个难题。
然而,Python 提供了一个functools.wraps() 装饰器,它可以将元数据从未装饰的函数复制到已装饰的包装函数中。让我们看看如何做到这一点。
如果我们试图打印出没有functools.wraps() 的伞状函数的元数据,那么返回的是包装器的名字,而不是伞状函数。
def umbrella_function(function):
"""I am the umbrella function """
# @functools.wraps(function)
def inner_function(args1, args2):
"""Inner docs"""
print("Arguments passed are: {0}, {1}".format(args1,args2))
function(args1, args2)
return inner_function
@umbrella_function
def another_function(name, age):
"""I am the another function """
print('So, {name} is {age} years old and she is a {occupation}'
.format(name = name, age = age, occupation = 'programmer'))
print(another_function.__name__)
print(another_function.__doc__)
输出。
inner_function
Inner docs
然而,如果我们使用functools.wraps() ,元数据就可以被访问。
def umbrella_function(function):
"""I am the umbrella function """
@functools.wraps(function)
def inner_function(args1, args2):
"""Inner docs"""
print("Arguments passed are: {0}, {1}".format(args1,args2))
function(args1, args2)
return inner_function
@umbrella_function
def another_function(name, age):
"""I am the another function """
print('So, {name} is {age} years old and she is a {occupation}'
.format(name = name, age = age, occupation = 'programmer'))
print(another_function.__name__)
print(another_function.__doc__)
输出:如果我们使用,元数据就可以被访问。
another_function
I am another function
umbrella_function
I am the umbrella function
使用多个装饰器
Python 允许同时使用多个装饰器。这个过程包括用相同或不同的装饰器对一个函数进行多次装饰。
为了使用多个装饰器,我们把装饰器放在所需函数的正上方。Python 会自动完成装饰器的连锁。
def umbrella_function(function):
def inner_function(args1, args2):
print("The first argument is: {0}".format(args1))
function(args1, args2)
return inner_function
def umbrella_function2(function):
def inner_function(args1, args2):
print("The second argument passed is: {0}".format(args2))
function(args1, args2)
return inner_function
@umbrella_function
@umbrella_function2
def another_function(name, age):
print ('So, {name} is {age} years old and she is a {occupation}'
.format(name = name, age = age, occupation = 'programmer'))
another_function('Mia', 18)
输出。
The first argument is: Mia
The second argument passed is: 18
So, Mia is 18 years old, and she is a programmer
结论
正如我们在上面看到的,Python 装饰器动态地改变了一个函数、方法或类的属性,而不直接改变代码片段。装饰器可以确保你的代码不是多余的,可以用来编写更干净的代码。