Python装饰器是程序开发中经常使用到的功能,熟练掌握装饰器会让你的编程思路更加广阔
要理解装饰器首先我们要理解以下两点:在 Python 中“函数是一等对象” 。即函数是一种特殊类型的变量,可以和其余变量一样,可以作为参数传递给函数,也可以作为返回值返回。Python 中的整数、字符串和字典等都是一等对象。
函数装饰器在导入模块时立即执行,而被装饰的函数只在明确调用时运行。
在讲装饰器之前,先要了解闭包
我们先看一段代码:
def outer(i):
j = 1
def inner():
x = i + j
print(x)
return inner
test = outer(5)
test()
#输出 6
在上边的代码中,我们有一个外部函数“outer()”和该函数的内部函数“inner()”,以及外部函数的局部变量“i”、“j”。在内部函数中我们使用了外部函数的局部变量,最后返回了内部函数的引用,也就是“inner”。
那么我们可以给闭包一个定义:通过调用含有一个内部函数加上该外部函数持有的外部局部变量的外部函数产生的一个实例函数。
一般情况下,如果一个函数结束,函数的内部所有东西都会被释放,局部变量都会消失。闭包是一种特殊情况,如果外函数在结束时发现有自己的临时变量将会在内部函数中用到,就会把这个临时变量绑定给了内部函数,然后再结束。
闭包就说到这,不在做过多的赘述,如果题主不是很明白可以再去查阅相关资料。
那么装饰器和闭包又有什么关系呢?
我们首先来看一下装饰器的概念:装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。
而实际上,装饰器就是一个闭包,把一个函数当做参数然后返回一个替代版函数。
以下是一个简单的例子:
假设现在有一个函数sayHi,用来输出一句话
def sayHi():
print('Hello, World')
s = sayHi
s()输出:Hello, World
我希望在不修改“sayHi”函数的情况下在其之前再输出一句话,这种在代码运行期间动态增加功能的方式,称之为“装饰器”。 本质上,装饰器就是一个返回函数的高阶函数我们可以这么写:
def sayName(func):
def inner():
print("I'm Yu")
return func
return inner()
def sayHi():
print('Hello, World')
s = sayName(sayHi)
s()输出:
I'm Yu
Hello, World
但代码美中不足的是,我们每次给sayHi增加功能都需要用到类似s = sayName(sayHi)这句话。
python为了简化这种情况,提供了一个语法糖“@”。简化上边的代码:
def sayName(func):
def inner():
print("I'm Yu")
return func()
return inner
@sayName
def sayHi():
print('Hello, World')
sayHi()输出:
I'm Yu
Hello, World
以上代码中,首先,在装饰器函数sayName中,sayName需要接受一个参数func,在其内部又定义了一个inner函数,在inner函数中增加一句输出,并返回func对象,然后sayName函数返回内部函数inner,其实就是一个闭包函数。
接下来在sayHi上边增加一个@sayName,其意义就是在python解释器之行到此处时,会调用装饰器函数"sayName",并把被装饰得函数"sayHi"作为参数传入。此时的sayHi已经不是未加装饰时的函数了,而是指向sayName.inner函数地址。在接下来调用sayHi()时,其实就是调用sayName.inner。
然后我们还可以对装饰器做更多的扩展。
有参函数装饰
之前的例子是对无参函数的装饰,如果装饰带参数的函数该如何处理?
def sayName(func):
def inner(name):
print("I'm Yu")
return func(name)
return inner
@sayName
def sayHi(name):
print('Hi,' + name)
sayHi('siri')输出:
I'm Yu
Hi,siri
两个装饰器装饰函数
这里测试两个装饰器装饰一个函数的结果:
def sayName(func):
print('name')
def inner():
print("I'm Yu")
return func()
return inner
def sayAge(func):
print('age')
def inner():
print("i'm 30")
return func()
return inner
@sayName
@sayAge
def sayHi():
print('Hello, World')
sayHi()输出:
age
name
I'm Yu
i'm 30
Hello, World
我们来分析一下输出这个结果的原因:
首先,python解释器执行到第一个装饰器@sayName,在接下来发现装饰器下边不是一个函数而是另一个装饰器,解释器会执行第二个的装饰器@sayAge,然后把sayHi函数传入装饰器,所以首先输出了“age”,当@sayAge装饰完成,此时的sayHi函数地址指向了sayAge.inner的地址,解释器会返回去执行@sayName装饰器来装饰新的sayHi,从而输出了“name”,接着函数当前指向sayName.inner会先输出“I'm Yu”,在这里返回的func()其实就是返回的sayAge.inner,所以在下面输出i'm 30,最后输出原本sayHi的“Hello, World”
有参装饰器
下边是装饰器带参数:
def now(time):
def sayName(func):
def inner(name):
print('现在是: %s' % time)
print("I'm Yu")
return func(name)
return inner
return sayName
@now('2016/10/30')
def sayHi(name):
print('Hello,' + name)
sayHi('siri')输出:
现在是: 2016/10/30
I'm Yu
Hello,siri
以上就是Python中,我对装饰器的理解,希望对题主有一定的帮助。