内容字号:默认大号超大号

段落设置:段首缩进取消段首缩进

字体设置:切换到微软雅黑切换到宋体

python-装饰器简述

2018-04-16 17:08 出处:清屏网 人气: 评论(0

装饰器是什么

用来修饰别的函数的函数就可以称之为装饰器

这种函数的参数一般就是另外一个函数

也就是说,调用这种函数,需要给这种函数传参,且参数是函数

@语法糖

@语法糖一般用来表示装饰器函数

不用@也可以达到装饰函数的目的 ,下面会有演示

函数嵌套

在一个函数中定义另外一个函数

def f1(arg="aaa"):
      def f2():
           return "hello"
      def f3():
          return "hi"
      def f4():
         return "haha"
      
     print f2()
     print f3()
     print f4()

这个f1函数有默认参数,所以可以不传参执行

执行f1()调用之后

执行结果如下:

hello

hi

haha

在函数里返回函数

def hi(arg="aaa"):
    def greet():
        return "bbb"

    def welcome():
        return "ccc"

    if arg == "aaa":
        return greet
    else:
        return welcome

a = hi()
print(a)
print (a())

这里同样使用了默认参数,则a = hi() 会命中 if arg == "aaa"这个逻辑

返回greet,注意在这里,greet是函数,不是字符串,如果是返回字符串,则要返回的是 return "greet"这种

上面这段代码执行的结果是

为什么是这样的执行结果呢?第一个地方 print(a),打印的是a = hi()的结果

我们可以看到,hi()的返回结果都是在return一个函数,要么是greet函数,要么是welcome函数

函数就是对应一个地址,所以第一处打印的是这个函数的地址

第二处做了a的调用,即a(),则打印返回的函数即greet函数执行的结果,即bbb

将函数作为参数传给另外一个函数

def hi():
    return "hi"

def hello(func):
    print("before func()")
    print(func())

hello(hi)

执行结果是

before func()

hi

这里把hi这个函数作为参数传给hello函数

hello函数先打印一句自身的输出before func()

再执行这个被传入的函数

我们可以看到,通过装饰器,我们可以在一个函数被调用前干一些需要的事情

不用@实现装饰器

def hi(a_func):

    def hello():
        print("I am doing some boring work before executing a_func()")

        a_func()

        print("I am doing some boring work after executing a_func()")
    return hello

def haha():
    print("I am the function which needs some decoration ")

haha = hi(haha)
print haha()

运行结果:

I am doing some boring work before executing a_func()

I am the function which needs some decoration

I am doing some boring work after executing a_func()

None

这个就是装饰器,起到了用hi函数装饰了haha函数的功能

那么怎么用@语法糖实现呢

def hi(a_func):

    def hello():
        print("I am doing some boring work before executing a_func()")

        a_func()

        print("I am doing some boring work after executing a_func()")
    return hello

@hi
def haha():
    print("I am the function which needs some decoration ")

haha()

可以看到,装饰器就是用希望装饰别的函数的函数,比如 ,希望用A装饰B

就在定义B函数的上一行,写上 @A

def A():
     pass
     
     
@A   
def B():
    pass

总结:理解就是装饰器其实就是这样一种函数:带参数的,且参数是另外一个函数的函数

使用装饰器的目的一般是为了在运行时改变函数的一些属性/行为,就可以给这个函数加上装饰器,让装饰器去在这个函数被调用前后,干一些你想做的事情

wraps干什么的?

我们修改下上面的代码,多记录一点东西

def hi(a_func):

    def hello():
        print("I am doing some boring work before executing a_func()")

        a_func()

        print("I am doing some boring work after executing a_func()")
    return hello

@hi
def haha():
    print("I am the function which needs some decoration ")

haha()
print(haha.__name__)

我们的意图是打印haha这个函数的函数名,但实际上打印的是hello

为什么?

因为haha这个函数使用装饰器之后,haha的行为部分被装饰器函数改变了

可以看到,用hi函数装饰了haha之后,返回的是hello函数,那么当我们需要拿到被装饰函数的函数名,还有其他属性的时候怎么做呢?

使用functools.wraps方法

from functools import wraps
 def hi(a_func):
   @wraps(a_func)
    def hello():
        print("I am doing some boring work before executing a_func()")

        a_func()

        print("I am doing some boring work after executing a_func()")
    return hello

@hi
def haha():
    print("I am the function which needs some decoration ")

haha()
print(haha.__name__)

执行结果如下:

I am doing some boring work before executing a_func()

I am the function which needs some decoration

I am doing some boring work after executing a_func()

haha

正是我们想要的结果

@wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。

举一个记录日志的例子

from functools import wraps

def logit(func):
    @wraps(func)
    def with_logging(*args, **kwargs):
        print(func.__name__ + " was called")
        return func(*args, **kwargs)
    return with_logging

@logit
def addition_func(x):
   """Do some math."""
   return x + x


result = addition_func(4)
# Output: addition_func was called
分享给小伙伴们:
本文标签: python装饰器

相关文章

发表评论愿您的每句评论,都能给大家的生活添色彩,带来共鸣,带来思索,带来快乐。

CopyRight © 2015-2016 QingPingShan.com , All Rights Reserved.

清屏网 版权所有 豫ICP备15026204号