Python学习记录——装饰器

一.函数即对象

1.函数是最高级的对象(对象是类的实例化,可以调用相应的方法,函数是包含变量对象的对象)

2.只有函数加载到内存才可以被调用

3.函数满足的两个条件:

(1)可以赋值给其他变量

如f1=f2这种表达式合理

(2)其可以被定义在另外一个函数内(作为参数&作为返回值),类似于整形,字符串等对象

函数名作为参数

  def foo(func):

    print('foo')

    func()

  def bar():

    print('bar')

  foo(bar)

函数名作为返回值 

  def foo():

    print('foo')

    return bar

  def bar():

    print('bar')

  b=foo()

  b()

二.闭包

1.引入:闭包涉及到嵌套函数,通过在函数内部def的关键字再声明一个函数即为嵌套:

  def outer():

    x = 1

    def inner():

      print (x) 

    return inner

  in_func=outer()

  in_func()

 不能直接赋值in_func=inner,因为没有执行outer之前inner并没有存入内存中,会出现找不到的错误

2.定义:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。即闭包=内部函数+定义函数时的环境。

3.解释:如上实例,inner就是内部函数,inner里引用了外部作用域的变量x(x在外部作用域outer里面,不是全局作用域),则这个内部函数inner就是一个闭包。

三.装饰器

1.意义:可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值也是一个函数对象

2.应用范围:插入日志、性能测试、事务处理、缓存、权限校验等应用场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。

3.简单装饰器:

(1)应用举例:(监测程序运行耗时)

  import time  #引入时间模块

  def show_time(f):

    def wrapper():

      start=time.time()

      f()

      end=time.time()

      print('spend %s seconds'%(end-start))  #采用格式化输出

    return wrapper   #装饰器返回值为函数对象

 

  @show_time  #等价于f1=show_time(f1)

  def f1():

    print('f1...')

    time.sleep(2)  #模仿程序运行时间

  f1()

(2)在这个例子中,函数进入和退出时 ,被称为一个横切面(Aspect),这种编程方式被称为面向切面的编程(Aspect-Oriented Programming)。 

(3)@符号是装饰器的语法,在定义函数的时候使用,避免再一次赋值操作

(4)如果有其他的类似函数,可以继续调用装饰器来修饰函数,而不用重复修改函数或者增加新的封装。这样,程序的可重复利用性提高了,并且程序的可读性增加了。

(5)注意:foo=show_time(foo)其实是把wrapper引用的对象引用给了foo,而wrapper里的变量func之所以可以用,就是因为wrapper是一个闭包函数

(6)装饰器在Python使用如此方便都要归因于Python的函数能像普通的对象一样能作为参数传递给其他函数,可以被赋值给其他变量,可以作为返回值,可以被定义在另外一个函数内。

4.带参数的被装饰函数

(1)应用举例:(若被监测函数原本带有参数,此处直接以不定长参数为例)

  import time  #引入时间模块

  def show_time(f):

    def wrapper(*args,**kwargs):

      start=time.time()

      f(*args,**kwargs)

      end=time.time()

      print('spend %s seconds'%(end-start))  #采用格式化输出

    return wrapper   #装饰器返回值为函数对象

 

  @show_time  #等价于f2=show_time(f2)

  def f2(*args,**kwargs):

    sum=0

    for i in args:

      sum+=i

    print(sum)

    time.sleep(2)  #模仿程序运行时间

  f2(1,2,3,4)  

5.带参数的装饰器:

(1)应用举例:(作用是通过参数,控制附加某些功能是否执行,作开关用)

  import time  #引入时间模块

  def time_log(flag=0):  #利用默认参数

    def show_time(f):

      def wrapper(*args,**kwargs):

        start=time.time()

        f(*args,**kwargs)

        end=time.time()

        print('spend %s seconds'%(end-start))  #采用格式化输出

        if flag:

          print('已将该操作记录至日志')

      return wrapper   #装饰器返回值为函数对象

    return show_time

 

  @time_log(1)    #设置打开写日志开关

  def f2(*args,**kwargs):

    sum=0

    for i in args:

      sum+=i

    print(sum)

    time.sleep(2)  #模仿程序运行时间

  f2(1,2,3,4)

(2)上面的time_log是允许带参数的装饰器。它实际上是对原有装饰器的一个函数封装,并返回一个装饰器(一个含有参数的闭包函数)。当使用@time_log(1)调用的时候,Python能够发现这一层的封装,并把参数传递到装饰器的环境中。

原文地址:https://www.cnblogs.com/zhoujianlin/p/8545214.html