• 学以致用三十六-----弄懂python装饰器


    看了海峰老师讲解的装饰器视频,讲解的非常棒。根据视频,记录笔记如下:

     装饰器:

    1、本质是函数,用def来定义。功能就是用来(装饰)其他函数,为其他函数添加附加功能

    现有两个函数如下,

    1 def test1():
    2     pass
    3 
    4 def test2()
    5     pass
    6 
    7 test1()
    8 test2()

    需要添加一个记录日志的功能

    原始方法,在每个函数里添加

     1  def test1():
     2      pass
     3      print('logging')
     4  
     5  def test2()
     6      pass
     7      print('logging')
     8  
     9  test1()
    10  test2()

    再进一步,增加一个函数,test1和test2来调用

     1 def logger():
     2     print('logging')
     3 
     4 def test1():
     5        pass
     6        logger()
     7   
     8 def test2()
     9        pass
    10        logger()
    11   
    12  test1()
    13  test2()

    那假如有上百上千个函数,并且是正常在线的代码,也这样处理吗?很显然这是不可能的

    因此装饰器的原则

    2、a. 不能修改被装饰的函数的源代码

          b.不能修改被装饰的函数的调用方式

    实现装饰器知识储备:

    3、a. 函数即“变量”

          b. 高阶函数

          c.嵌套函数

    高阶函数+嵌套函数==装饰器

    ============================================

    再来看一下以下几个场景

    场景一

    1 def bar():
    2     print("in the bar")
    3 
    4 def foo():
    5     print ("in the foo")
    6     bar()
    7     
    8 foo()

    场景二

    1 def foo():
    2     print ("in the foo")
    3     bar()
    4     
    5 def bar():
    6     print("in the bar")
    7 
    8 foo()

    场景一和场景二的不同之处在于,一个bar()在foo()之前,一个在foo()之后,但两者结果一样,按理说python应该是从上往下一行一行执行,为啥场景二也没有问题呢

    经过断点debug调试,发现在debug的过程中,程序会先把函数都过一遍,顺序是   def  foo()  ---->  def bar()  ---->  foo()  ----> print ("in the foo")   ---> bar() -----> print (in the bar)

    那再看场景三

    1 def foo():
    2     print ("in the foo")
    3     bar()
    4 
    5 foo()
    6 
    7 def bar():
    8     print("in the bar")

    按照之前的解释,程序也会先把函数都过一遍,然后去执行。但场景三确报错了,会提示 name 'bar' is not defined,debug显示 def foo() 后直接到 foo(), 就直接执行foo()函数了,并没有往下走。

    因为遇到foo(),就表示要去执行foo函数,而此时 bar并未在内存建立‘’门牌号‘’,因此会报错

    看下面这张图,函数相当于变量的集合。

     

    高阶函数:

    a:把一个函数名当做实参传给另外一个函数

    (在不修改被装饰函数源代码的情况下为其添加功能)

    b:返回值中包含函数名(不修改函数的调用方式),一定要有return,返回该函数的内存地址

    如下面的代码

     1 import time
     2 def bar():
     3     time.sleep(3)
     4     print('in the bar')
     5 
     6 def test1(func):
     7     start_time = time.time()
     8     func()
     9     stop_time = time.time()
    10     print("the func run time is %s" %(stop_time-start_time))
    11 
    12 test1(bar)

    此时相当于   func=bar, func()  会执行bar函数

    执行结果

    in the bar
    the func run time is 3.0004918575286865

    返回值包含函数名,如

     1 import time
     2 def bar():
     3     time.sleep(3)
     4     print('in the bar')
     5 
     6 def test2(func):
     7     print(func)
     8     return func
     9 
    10 test2(bar)
    11 print("================")
    12 print(test2(bar))

    结果

    <function bar at 0x000001B343BF3EA0>
    ================
    <function bar at 0x000001B343BF3EA0>
    <function bar at 0x000001B343BF3EA0>

     print(test2(bar))先打印 func,然后返回func的内存地址。于是又打印一遍  

    换一种方式

     1 import time
     2 def bar():
     3     time.sleep(3)
     4     print('in the bar')
     5 
     6 def test2(func):
     7     print(func)
     8     return func
     9 
    10 t=test2(bar)
    11 print("================")
    12 # print(test2(bar))
    13 t()

    此时会去执行bar函数

    结果

    <function bar at 0x00000246AECB3EA0>
    ================
    in the bar

    那把 t  换成  bar 呢

     1 import time
     2 def bar():
     3     time.sleep(3)
     4     print('in the bar')
     5 
     6 def test2(func):
     7     print(func)
     8     return func
     9 
    10 bar=test2(bar)
    11 print("================")
    12 # print(test2(bar))
    13 bar()

    结果和上面是一样的。可以看出函数的调用方式没有改变,结果是一样的

    因此引出了装饰器

     1 import time
     2 def test2(func):
     3     # print(func)
     4     print("auth---")
     5     return func
     6 
     7 @test2
     8 def bar():
     9     time.sleep(1)
    10     print('in the bar')
    11 bar()

    执行结果:

    auth---
    in the bar

    在 in  the  bar 前面加了一段auth---,没有改变bar()的代码

    这样装饰器就解释明白了

    当然还有多层嵌套和装饰,带参数的装饰器,以后需要加强练习再补充。

  • 相关阅读:
    NET中的幕后英雄:MSCOREE.DLL (转载)
    【百度地图API】如何使用suggestion下拉列表方式的搜索建议
    经典收藏 50个jQuery Mobile开发技巧集萃
    深入理解Android消息处理系统——Looper、Handler、Thread
    Android GridView宫格视图(一) 运用BaseAdapter
    Toast和Handler的间隔使用
    android Toast大全(五种情形)建立属于你自己的Toast
    SQL 新特性 output
    通过Aspose.Cells.dll组件,实现多sheet导出Xls
    SQL 通过镜像数据库实现 故障自动切换
  • 原文地址:https://www.cnblogs.com/liongong/p/9927048.html
Copyright © 2020-2023  润新知