• Python装饰器(函数)


    闭包

    1.作用域L_E_G_B(局部、内嵌、全局...):

    1 x=10#全局
    2 
    3 def f():
    4     a=5 #嵌套作用域
    5     def inner():
    6         count = 7 #局部变量
    7         print a
    8         return 1

    从内往外寻找 a 。

    2.高阶函数

    a.函数名可以作为参数输入

    b.函数名可以作为返回值

    3.闭包

     1 def outer():
     2     x=10
     3     def inner(): #条件1 inner是内部函数
     4         print(x) #条件2 外部环境的一个变量
     5 
     6     return inner #结论: 内部函数inner就是一个闭包
     7 
     8 outer()()#调用inner
     9 #同上
    10 f = outer()#获得inner
    11 f()#调用执行inner
    12 
    13 #不能直接调用inner,因为inner为局部变量,全局无法调用

    执行结果

    10
    10
    
    Process finished with exit code 0

    第10行,获得inner变量,第11行执行inner函数,而执行inner函数时(在外部执行),其中x变量既不属于inner函数内部变量,也不属于全局变量,按理应该报错却没报错,这种现象称为闭包。

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

    在内部函数里(inner函数中),对在外部作用域的变量(x)进行引用(print),那么内部函数(inner)就被认为是闭包。

    装饰器

     1 import time
     2 
     3 def foo():
     4     print("foo.....")
     5     time.sleep(2)
     6 
     7 def bar():
     8     print("bar.....")
     9     time.sleep(3)
    10 
    11 def show_time(f): #函数名作参数
    12     start = time.time()
    13     f()
    14     end = time.time()
    15     print("spend %s" % (end - start))
    16 
    17 
    18 show_time(bar)

    函数名作参数,减少重复代码。

    执行结果:

    bar.....
    spend 3.0022976398468018
    
    Process finished with exit code 0

     但是以上方法改变了调用方式,加上所需时间功能后,不是直接用foo,而是用show_time,这样对所有使用foo函数的代码都需修改,违背了封闭开放原则。

     1 import time
     2 
     3 def foo():
     4     print("foo.....")
     5     time.sleep(2)
     6 
     7 def bar():
     8     print("bar.....")
     9     time.sleep(3)
    10 
    11 def show_time(f): #函数名作参数 ,装饰器
    12     def inner():
    13         start = time.time()
    14         f()
    15         end = time.time()
    16         print("spend %s" % (end - start))
    17     return inner
    18 
    19 foo = show_time(foo)
    20 foo()

    show_time即为装饰器,inner函数为闭包,f函数名变量即为外部作用域变量。

    执行结果:

    foo.....
    spend 2.00213360786438
    
    Process finished with exit code 0

    但是以上方法还需要自己赋值,不够简便、优雅。

    优雅的写法:

     1 import time
     2 
     3 def show_time(f): #函数名作参数 ,装饰器
     4     def inner():
     5         start = time.time()
     6         f()
     7         end = time.time()
     8         print("spend %s" % (end - start))
     9     return inner
    10 
    11 @show_time  #  foo = show_time(foo), 给foo函数添加一个计算所需时间的功能
    12 def foo():
    13     print("foo.....")
    14     time.sleep(2)
    15 
    16 #foo = show_time(foo)
    17 foo()

    11行,给foo函数添加一个计算所需时间的功能,@show_time,可理解为foo = show_time(foo)

    执行结果:

    foo.....
    spend 2.002133369445801
    
    Process finished with exit code 0

     被装饰函数参数(功能函数加参数):

     1 import time
     2 
     3 def show_time(f): #函数名作参数 ,装饰器
     4     def inner(x, y):
     5         start = time.time()
     6         f(x, y)
     7         end = time.time()
     8         print("spend %s" % (end - start))
     9     return inner
    10 
    11 @show_time  #  add = show_time(add), 给add函数添加一个计算所需时间的功能
    12 def add(a, b):
    13     print(a + b)
    14     time.sleep(1)
    15 
    16 #foo = show_time(foo)
    17 add(1, 2)

    执行结果:

    3
    spend 1.0010321140289307
    
    Process finished with exit code 0

    不定长参数:

     1 import time
     2 
     3 def show_time(f): #函数名作参数 ,装饰器
     4     def inner(*x, **y):
     5         start = time.time()
     6         f(*x, **y)
     7         end = time.time()
     8         print("spend %s" % (end - start))
     9     return inner
    10 
    11 @show_time
    12 def add(*a, **b): # a为元组
    13     sums = 0
    14     for i in a:
    15         sums += i
    16     print(sums)
    17     time.sleep(1)
    18 
    19 
    20 add(1, 2, 5, 7, 9)#不定长参数

    其中a为元组。

    执行结果:

    24
    spend 1.0011086463928223
    
    Process finished with exit code 0

    装饰器参数:

     1 import time
     2 
     3 def logger(flag=''):#默认空
     4 
     5     def show_time(f):  # 函数名作参数 ,装饰器
     6         def inner(*x, **y):
     7             start = time.time()
     8             f(*x, **y)
     9             end = time.time()
    10             print("spend %s" % (end - start))
    11             if flag == 'true':
    12                 print('日志记录')
    13         return inner
    14     return show_time
    15 
    16 def show_time(f): #函数名作参数 ,装饰器
    17     def inner(*x, **y):
    18         start = time.time()
    19         f(*x, **y)
    20         end = time.time()
    21         print("spend %s" % (end - start))
    22     return inner
    23 
    24 @logger('true') # 相当于@show_time,不过有了一个flag变量,相当于闭包
    25 def add(*a, **b): # a为元组
    26     sums = 0
    27     for i in a:
    28         sums += i
    29     print(sums)
    30     time.sleep(1)
    31 
    33 add(1, 2, 5, 7, 9)#不定长参数
    34 
    35 @logger()
    36 def bar():
    37     print("bar......")
    38     time.sleep(3)
    39 
    40 bar()

    装饰器加参数flag,决定是否输出日志,此时show_time为闭包。

    执行结果:

    24
    spend 1.001152515411377
    日志记录
    bar......
    spend 3.00311541557312
  • 相关阅读:
    实用的网络流量监控脚本
    校园招聘面试总结
    简单的HttpClient使用
    大日志处理问题
    <Interview Problem>最小的“不重复数”
    <Interview Problem>二叉树根到叶节点求和值匹配
    安装后端阿里云sdk
    ModuleNotFoundError: No module named 'Crypto'
    pip install 报错 ERROR: Could not find a version that satisfies the requirement PIL (from versions: none) ERROR: No matching distribution found for PIL
    dva+antd初体验
  • 原文地址:https://www.cnblogs.com/112358nizhipeng/p/9471695.html
Copyright © 2020-2023  润新知