zoukankan      html  css  js  c++  java
  • 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能够发现这一层的封装,并把参数传递到装饰器的环境中。

  • 相关阅读:
    ubuntu系统上常用的开发工具
    wamp环境下安装pear
    PHP中preg_match_all函数用法使用详解
    晚睡对策
    iphone相关
    090213 阴
    月曜日の予定(10:30までREVIEW  10:00まで完成予定)
    一个通知
    我还没走
    星期5
  • 原文地址:https://www.cnblogs.com/zhoujianlin/p/8545214.html
Copyright © 2011-2022 走看看