PHP前端开发

Python中装饰器是什么?

百变鹏仔 3小时前 #Python
文章标签 Python

本篇文章给大家带来的内容是关于python中装饰器是什么?python中装饰器的介绍,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

一、什么是装饰器

装饰器,decorator,本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。

装饰器通过不修改核心代码而增强核心代码部分的功能。例如在函数前插入日志、权限校验、事务处理等场景。
而且可以抽离出大量与函数功能无关的雷同代码并重用。

二、早期实现:不是装饰器的装饰器

  • Python中函数也可以看做是一个对象,可以赋值给变量,并通过变量调用该函数。

例如:

立即学习“Python免费学习笔记(深入)”;

def foo():   print("2017-06-08")f = foo    # 将函数赋值给变量,f为函数对象f()# 返回结果:2017-06-08

三、语法糖@ 实现简单装饰器

假设现在要增强foo()的功能,例如,在函数调用前打印日志。但是又不希望修改foo()函数的定义。在这种代码运行期间动态增加功能的方式,称之为“装饰器”。
如下:

def testfunc(func):    print('testfunc')    def wrapper():        print("%s %s() called" %(time.ctime(),func.__name__))        return func()    return wrapper@testfunc def foo():    print('foo1()')foo()  # 相当于执行testfunc(foo) ->wrapper(foo) -> foo()

执行结果:

testfuncWed Sep 12 15:01:13 2018 foo() calledfoo1()

说明:执行foo()前,先执行testfunc(foo),再执行wrapper(),返回时调用foo()本身。

四、接收特定类型参数的装饰器

  • 装饰器可以接收参数,当调用装饰器返回的函数时,也就调用了包裹函数,把参数传入包裹函数,它将参数传递给被装饰的函数。

如下:

def testfunc_with_args(func):    def wrapper_argus(arg1, arg2):        print("I got args! Look:", arg1, arg2)        func(arg1, arg2)    return wrapper_argus@testfunc_with_argsdef full_name(first_name, last_name):  # 带参数,将参数传给被装饰的函数    print("My name is", first_name, last_name)full_name("Peter", "Venkman")  # 调用

执行结果:

I got args! Look: Peter VenkmanMy name is Peter Venkman

五、带不定参数的装饰器

当有多个函数需要调用装饰器,但是函数的参数各不同时,该如何实现呢?总不能一个函数对应一个装饰器吧。这时候就可以用带不定参数的装饰器进行实现。
如下:

def log(func):    def wrapper(*args,**kwargs):        # 可接受各种参数        print('call %s():'% func.__name__)        return func(*args,**kwargs)     # 返回一个函数    return wrapper                      # 装饰器返回一个函数,进入到wrapper()@log      # @log放到now()的定义处,相当于执行语句:now = log(now)def now_1(a,b):    print('now()1:a+b = ',a+b)@logdef now_2(a,b,c):    print('now_2():a+b+c = ',a+b+c)now_1(1,2)now_2(1,2,3)

运行一下哦~

六、多个装饰器

当一个函数想要加入多项功能时,可以考虑使用多层装饰器,就是要注意一下装饰器的执行顺序。
举个栗子:

# 注意代码的执行顺序def deco_1(func):    print('------111111------')    def wrapper(*args,**kwargs):    # 包裹函数,参数与原函数的参数一致        print('start: this is deco_1.')        func(*args,**kwargs)        print('end: deco_1.')    return wrapper  # 返回值是一个包裹函数def deco_2(func):    print('------222222------')    def wrapper(*args,**kwargs):        print('start: this is deco_2.')        func(*args,**kwargs)        print('end: deco_2.')    return wrapper@deco_1@deco_2def now_1(a,b):    print('now()1:a+b = ',a+b)now_1(1,2)

运行结果:

# 结果,注意执行顺序:------222222------------111111------start: this is deco_1.start: this is deco_2.now()1:a+b =  3end: deco_2.end: deco_1.

七、装饰器本身带参数

除了给被装饰的函数带参数,装饰器本身也可以带参数。

def logging(level):    def wrapper(func):        def inner_wrapper(*args, **kwargs):            print("[{level}]: enter function {func}()".format(level=level, func=func.__name__))            return func(*args, **kwargs)        return inner_wrapper    return wrapper    @logging(level='INFO')def say(something):    print("say {}!".format(something))@logging(level='DEBUG')def do(something):    print("do {}...".format(something))say('hello')do("my work")

执行结果:

# 执行结果:[INFO]: enter function say()say hello![DEBUG]: enter function do()do my work...