Python @函数装饰器及用法(超级详细)

7个月前 (04-27)
前面章节中,我们已经讲解了 Python 内置的 3 种函数装饰器,分别是 @staticmethod、@clasethod 和 @property,其中 staticmethod()、clasethod() 和 property() 都是 Python 的内置函数。

那么,函数装饰器的工作原理是怎样的呢?假设用 funA() 函数装饰器去装饰 funB() 函数,如下所示:

#funA 作为装饰器函数

def funA(fn):

#...

fn() # 执行传入的fn参数

#...

return '...'

@funA

def funB():

#...


实际上,上面程序完全等价于下面的程序:

def funA(fn):

#...

fn() # 执行传入的fn参数

#...

return '...'

def funB():

#...

funB = funA(funB)

通过比对以上 2 段程序不难发现,使用函数装饰器 A() 去装饰另一个函数 B(),其底层执行了如下 2 步操作:

  1. 将 B 作为参数传给 A() 函数;

  2. 将 A() 函数执行完成的返回值反馈回  B。


举个实例:

#funA 作为装饰器函数

def funA(fn):

print("C语言中文网")

fn() # 执行传入的fn参数

print("http://c.biancheng网站站点" rel="nofollow" /> C语言中文网
学习 Python

http://c.biancheng网站站点" rel="nofollow" />

print(funB)

其输出结果为:

装饰器函数的返回值

显然,被“@函数”修饰的函数不再是原来的函数,而是被替换成一个新的东西(取决于装饰器的返回值),即如果装饰器函数的返回值为普通变量,那么被修饰的函数名就变成了变量名;同样,如果装饰器返回的是一个函数的名称,那么被修饰的函数名依然表示一个函数。

实际上,所谓函数装饰器,就是通过装饰器函数,在不修改原函数的前提下,来对函数的功能进行理的扩充。

带参数的函数装饰器

在分析 funA() 函数装饰器和 funB() 函数的关系时,细心的读者可能会发现一个问题,即当 funB() 函数无参数时,可以直接将 funB 作为 funA() 的参数传入。但是,如果被修饰的函数本身带有参数,那应该如何传值呢?

比较简单的解决方法就是在函数装饰器中嵌套一个函数,该函数带有的参数个数和被装饰器修饰的函数相同。例如:

def funA(fn):

# 定义一个嵌套函数

def say(arc):

print("Python教程:",arc)

return say

@funA

def funB(arc):

print("funB():", a)

funB("http://c.biancheng网站站点" rel="nofollow" />

Python教程: http://c.biancheng网站站点" rel="nofollow" />

def funA(fn):

# 定义一个嵌套函数

def say(arc):

print("Python教程:",arc)

return say

def funB(arc):

print("funB():", a)

funB = funA(funB)

funB("http://c.biancheng网站站点" rel="nofollow" />

def funA(fn):

# 定义一个嵌套函数

def say(*args,**kwargs):

fn(*args,**kwargs)

return say

@funA

def funB(arc):

print("C语言中文网:",arc)

@funA

def other_funB(name,arc):

print(name,arc)

funB("http://c.biancheng网站站点" rel="nofollow" /> C语言中文网: http://c.biancheng网站站点" rel="nofollow" />

@funA

@funB

@funC

def fun():

#...

上面程序的执行顺序是里到外,所以它等效于下面这行代码:

fun = funA( funB ( funC (fun) ) )

这里不再给出具体实例,有兴趣的读者可自行编写程序进行测试。