python函数装饰器(修饰符)

前提知识点

  1. 可以将一个函数赋值给一个变量 备注:赋值时候不带函数括号,带函数括号表示调用函数
  2. 可以在函数中定义另外的函数,那么在执行外层函数时候,里面的函数也会执行
  3. 从函数中返回函数,返回的函数不带函数括号,带函数括号表示调用函数
  4. 将函数作为参数传给另一个函数

具体实例见:https://www.runoob.com/w3cnote/python-func-decorators.html

装饰器的作用

python函数修饰器@的作用是在不改变其它函数的情况下,为其它函数增加额外的功能,常用于插入日志、性能测试、事务处理等等。

装饰器的定义

装饰器指的定义一个函数,该函数是用来为其他函数添加额外的功能。装饰器本身也是一个函数,如下面的funA()就是装饰器函数,funB()为被装饰的函数。

装饰器的处理逻辑

当解释器读到@装饰符,会先解析@下一行的内容,把下一行的函数作为@后边的函数的参数,执行装饰器函数。并把装饰器函数的返回值返回给被装饰的函数。即如下面的函数funB,将作为函数funA参数,因为定义函数funA的时候,入参函数也嵌套在函数funA里面执行,因此,在执行函数funA的时候也会执行函数funB。执行完装饰器函数funA后,将返回值返回给被装饰的函数funB。整个过程也即等价于funB = funA(funB)

举例说明

#funA 作为装饰器函数
def funA(fn):
    print("C语言中文网")
    fn() # 执行传入的fn参数
    print("http://c.biancheng.net")
    return "装饰器函数的返回值"

@funA
def funB():
    print("学习 Python")

程序执行流程为:

C语言中文网
学习 Python
http://c.biancheng.net

在此基础上,如果在程序末尾添加如下语句:print(funB)

如下代码:

#funA 作为装饰器函数
def funA(fn):
    print("C语言中文网")
    fn() # 执行传入的fn参数
    print("http://c.biancheng.net")
    return "装饰器函数的返回值"

@funA
def funB():
    print("学习 Python")
print(funB)

其输出结果为:

C语言中文网
学习 Python
http://c.biancheng.net
装饰器函数的返回值

这里面存在的返回值“装饰器函数的返回值”,说明将返回值赋给了被装饰的函数funB

上面的程序等价于:

#funA 作为装饰器函数
def funA(fn):
    print("C语言中文网")
    fn() # 执行传入的fn参数
    print("http://c.biancheng.net")
    return "装饰器函数的返回值"

def funB():
    print("学习 Python")

funB = funA(funB)

1:被装饰函数不带参数

即当 funB() 函数无参数时,可以直接将 funB 作为 funA() 的参数传入。

#funA 作为装饰器函数
def funA(fn):
    print("C语言中文网")
    fn() # 执行传入的fn参数
    print("http://c.biancheng.net")
    return "装饰器函数的返回值"

@funA
def funB():
    print("学习 Python")

运行结果:

C语言中文网
学习 Python
http://c.biancheng.net

2:被修饰函数带参数

被装饰函数如果带参数,并且也有可能多个函数被同一个装饰器函数修饰,而且这些函数带有的参数个数并不相等,怎么办呢?

最简单的解决方式是用 *args 和 **kwargs 作为装饰器内部嵌套函数的参数,*args 和 **kwargs 表示接受任意数量和类型的参数。

思路:先定义装饰器函数,将被装饰的函数做为入参,然后在装饰器函数里面嵌套定义一个函数,将*args 和 **kwargs 做为入参,嵌套

的函数执行被装饰的函数。

例如:

def funA(fn):
    # 定义一个嵌套函数
    def fn1(*args,**kwargs):
        fn(*args,**kwargs)
    return fn

@funA
def funB(arc):
    print(arc)


@funA
def other_funB(name,arc):
    print(name,arc)

funB("http://c.biancheng.net")
other_funB("Python教程:","http://c.biancheng.net/python")

运行结果:

http://c.biancheng.net
Python教程: http://c.biancheng.net/python

函数装饰器可以嵌套

Python 也支持多个装饰器,如:

@funA
@funB
@funC
def fun():
    #...

它等效于下面这行代码:

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

在函数定义中我们返回函数,为什么是函数名,而不是函数名()。为什么那样?这是因为当你把一对小括号放在后面,这个函数就会执行;然而如果你不放括号在它后面,那它可以被到处传递,并且可以赋值给别的变量而不去执行它。也即将函数作为参数、将函数作为返回值、将函数赋值给另一个变量等都不用带括号,只需要函数名

将函数做为参数举例:

def hi():
    return "hi yasoob!"
 
def doSomethingBeforeHi(func):  #将函数作为参数
    print("I am doing some boring work before executing hi()")
    print(func())  #将作为参数的函数在被定义的函数中执行并打印出来
 
doSomethingBeforeHi(hi)
#outputs:I am doing some boring work before executing hi()
#        hi yasoob!

你可能感兴趣的:(Python,python,开发语言,装饰器)