zoukankan      html  css  js  c++  java
  • 十九、python沉淀之路--装饰器

    一、实现装饰器的预备知识

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

    1、高价函数定义:

        1.函数接收的参数是一个函数名
        2.函数的返回值是一个函数名
        3.满足上述条件任意一个,都可称之为高阶函数

    例1:铺垫

     1 import time
     2 #例1
     3 def fn():
     4     print('这是被调用函数')
     5     time.sleep(2)
     6 
     7 def test(func):
     8     print('高阶函数将要开始运行')
     9     start_time = time.time()
    10     func()
    11     end_time = time.time()
    12     print('被调用函数的运行时间%s'%(end_time - start_time))
    13 
    14 test(fn)
    View Code

    例2

     1 #例2
     2 import time
     3 def fn():
     4     print('这是被调用函数')
     5     time.sleep(2)
     6 def test(func):
     7     print('正在执行高阶函数')
     8     return func
     9 #第一种调用
    10 f = test(fn)
    11 print(f)
    12 f()
    13 
    14 ## 第二种调用,升级版 :将调用函数test(func)的返回值赋值给一个与被调用函数fn()同名的变量fn,最后实现的效果就是
    15                       #(1)不改变被调用函数fn()的源代码
    16                       #(2) 不改变被调用函数fn()的调用方式
    17 fn = test(fn)
    18 print(fn)
    19 fn()
    View Code
    1 正在执行高阶函数
    2 <function fn at 0x0000017065C999D8>
    3 这是被调用函数
    4 正在执行高阶函数
    5 <function fn at 0x0000017065C999D8>
    6 这是被调用函数
    View Code
    
    
    升级版 :将调用函数test(func)的返回值赋值给一个与被调用函数fn()同名的变量fn,最后实现的效果就是
    1)不改变被调用函数fn()的源代码
    2) 不改变被调用函数fn()的调用方式

     例3  这种情况出现的结果是 多运行了一行

     1 # 例3
     2 import time
     3 def fn():
     4     print('这是被调用函数')
     5     time.sleep(2)
     6 
     7 def test(func):
     8     print('开始执行调用函数')
     9     start_time = time.time()
    10     func()
    11     end_time = time.time()
    12     return func      # 这种情况出现的结果是 多运行了一行
    13 
    14 fn = test(fn)
    15 fn()
    View Code
    1 开始执行调用函数
    2 这是被调用函数
    3 这是被调用函数
    View Code

    例4

     1 #例4
     2 def fn():
     3     print('这是被调用函数')
     4 def test(func):
     5     print('正在执行高阶函数')
     6     res = func()
     7     print('被调用函数执行完毕')
     8     return res
     9 
    10 fn = test(fn)
    11 # fn()     # 报错  :TypeError: 'NoneType' object is not callable
    View Code
    1 正在执行高阶函数
    2 这是被调用函数
    3 被调用函数执行完毕
    View Code
    即使赋了一个值,也还是解决不了多打印一行的结果。所以单层函数解决不了这个问题

    高阶函数总结:
    1、函数接收的参数是一个函数名
        作用:在不修改函数源代码的前提下,为函数添加新功能。
        不足:会改变函数的调用方式。
    2、函数的返回值是一个函数名:
        作用:不修改函数的调用方式
        不足:不能添加新功能。

    二、嵌套函数

     定义:

     1 def father(name):
     2     print('%s is from father'%name)
     3     def son():
     4         print('I am BeiJing,My fahter is %s'%name)
     5         def grandson():
     6             print('I am HaiDian,My grandfather is %s'%name)
     7         grandson()
     8     son()
     9     # print(locals())
    10 
    11 father('china')
    1 china is from father
    2 I am BeiJing,My fahter is china
    3 I am HaiDian,My grandfather is china

    详解在我的另外一篇博客里面:http://www.cnblogs.com/jianguo221/p/8984618.html

    三、实现装饰器(步骤进化)(重点中的重点)

     1 #进化版############################################################3
     2 import time
     3 def outer(func):
     4     def inner():
     5         print('开始运行被测试函数')
     6         start_time = time.time()
     7         func()
     8         end_time = time.time()
     9         print('被测试函数的运行时间是:%s'%(start_time - end_time))
    10     return inner
    11 
    12 def test():
    13     print('正在运行这个测试函数')
    14     time.sleep(2)
    15 # 慢慢实现装饰器
    16 #第一种调用方式
    17 f = outer(test)     #这条语句返回的就是inner的地址,即函数体
    18 f()
    19 
    20 #第二种调用方式
    21 inner = outer(test)    ##这条语句返回的就是inner的地址,即函数体
    22 inner()
    23 #由于第二种调用方式  和 第一种调用方式实现的效果是一样的。所以就满足了 装饰器的两个条件:
    24                      #(1)不改变被调用函数test()的源代码
    25                      #(2) 不改变被调用函数test()的调用方式
    26 #继续过度:由于第二种方式满足了装饰器调用的两个条件,就可以用  装饰器的一个 语法糖  形式来替换第二种形式,
    27           #以便实现简便操作  , 即加一个  @outer  .如下面的例子
    28 #加语法糖
    29 #终极版###################################
    30 import time
    31 def outer(func):
    32     def inner():
    33         print('开始运行被测试函数')
    34         start_time = time.time()
    35         func()
    36         end_time = time.time()
    37         print('被测试函数的运行时间是:%s'%(start_time - end_time))
    38     return inner
    39 @outer
    40 def test():
    41     print('正在运行这个测试函数')
    42     time.sleep(2)
    43 
    44 #加了语法糖后,调用方式就简单很多,只需要这样写就好了。语法糖  @outer  就等价于  test =outer(test)
    45 test()

    运行结果:

    1 开始运行被测试函数
    2 正在运行这个测试函数
    3 被测试函数的运行时间是:-2.000378370285034
    4 开始运行被测试函数
    5 正在运行这个测试函数
    6 被测试函数的运行时间是:-2.0004947185516357
    7 开始运行被测试函数
    8 正在运行这个测试函数
    9 被测试函数的运行时间是:-2.0002481937408447
  • 相关阅读:
    1104--DNA排序
    poj1050-To the Max
    编译:一个 C 程序的艺术之旅(转载)
    大话同步/异步、阻塞/非阻塞(转载)
    Windows 在 git bash下使用 conda 命令
    Python Multiprocessing 多进程,使用多核CPU计算 并使用tqdm显示进度条
    Python 写入训练日志文件并控制台输出
    nn.Conv2d 参数及输入输出详解
    Python中 list, numpy.array, torch.Tensor 格式相互转化
    Linux 上传代码到github
  • 原文地址:https://www.cnblogs.com/jianguo221/p/8983729.html
Copyright © 2011-2022 走看看