• python--闭包、装饰器


    1、闭包

    ①、python中一切皆对象,函数中嵌套函数肯定也是合理的,这种函数也叫作内嵌函数(内部函数)

    ②、内嵌函数只能被外部函数调用,被外部函数以外的区域被调用,就会出错!!!

    ③、若内部函数引用了外部函数的变量,或者外部函数以外的变量,那么!!这个内部函数就叫做闭包

    例子:

    ④、闭包的作用:定义-->闭包可以将其自己的代码和作用域以及外部函数的作用结合在一起

    按照上面的例子通俗的理解闭包就是:

    1 本来count仅实现了两个数量相加的功能
    2 
    3 由于闭包函数sum,给这个原有的的功能上又新增了一个功能
    4 
    5 因此可得,增加了闭包函数,在不改变原有功能的情况下修饰了原有函数,。使函数的功能可以变得更丰富---->由此引入装饰器的概念,其实和闭包的作用都是一样的,都是为了装饰原有函数的功能

    2、装饰器

    ①、理解了上述闭包的概念,那么其实装饰器的本质也是一个函数(确切的说是一个闭包函数)

    ②、常见使用场景:插入日志(这个在测试过程中有用)、性能测试、事务处理、权限校验

    ③、用法:创建一个装饰器,其实就是创建一个普通def函数

    ④、有返回值的函数被装饰之后依然有返回值,没有返回值的函数被装饰之后则没有返回值,符合我们想要的结果。

    1 
    #装饰器不正规的书写方法
    def
    decorator(func):----->装饰器的参数是一个方法(方法名), 2 func() 3 print('this is decorator')---->正常情况下,装饰器初始化完成,装饰器应该(return)返回一个可调用的对象,很明显,这边没有 4 5 @decorator 6 def target():---->原功能函数,其功能是打印一段文字 7 print('this is target') 8 target;---------->执行原功能函数时,若这个函数带有@装饰器,那么会直接开始执行这个装饰器函数,并把原函数当做参数传入;注意:此处的函数的调用方法是错误的,但是使用正确的调用方法会报错,下面会解释
    #最终输出

    问题:我发现如果执行原函数时使用target(),会提示TypeError: 'NoneType' object is not callable错误,但是去掉括号,直接用target调用,则正常,这又是为什么呢?有没有人知道可以解答一下呢??

    原理:会发生上面错误的原因,不是因为装饰器的代码写的不对,并非错误,只不过是一种不友好的装饰器,这就是为什么明明使用的是错误的调用方法,但是仍然能运行,那是因为我们把装饰器函数写成了不可被调用的函数。具体:https://www.tuicool.com/articles/FBZvya

     因此!!!把上面的代码改为:

    #装饰器的正确格式
    def
    decorator(func): def dec2(): func(); print('this is decorator'); return dec2;------------->装饰器返回一个函数(而函数是可调用的对象)~上面的写法返回的对象是str对象,是不可调用的 @decorator def target(): print('this is target') target();------->此处使用正确的调用函数方法,正常运行。
     

    3、装饰器的具体实践例子

    
    
     1 #通过银行卡存取款来模拟
     2 #一个函数里又实现了另外一个函数,这样实际已经违背了函数的开放封闭原则
     3 
     4 # 以下方法实现了在不改变原函数功能,以及原函数的调用方式的情况下,拓展了原功能的功能
     5 # 那么注意现在:除了check_mima(func)这个方法以外,其他方法不能再动了!!!!!!!!,这样才能真正理解到装饰器的魅力丫
     6 
     7 #以下方法实现了在不改变原函数功能,以及原函数的调用方式的情况下,拓展了原功能的功能
     8 #注意看下面优化后的函数,是不是很熟悉,内部函数使用了外部函数的变量(func),所以这是一个闭包啊
     9 def check_mima(func):
    10     def inner():
    11         print('密码校验中')
    12         func();
    13     return inner;
    14 
    15 @check_mima
    16 def cunkuan():
    17     #check_mima();
    18     print('存款中.....');
    19 
    20 @check_mima
    21 def qukuan():
    22     #check_mima();
    23     print('取款中...');
    24 
    25 
    26 
    27 #qukuan=check_mima(qukuan);
    28 #cunkuan=check_mima(cunkuan);
    29 
    30 #一个简单的方法,按下按钮1则存款,否则为取款(方法简单粗暴)
    31 #在存取款操作之前加上了密码校验,但明显代码冗余还是很高
    32 #可想而知,如果再加上查询、等其他业务,代码的冗余岂不是越来越高
    33 
    34 button=1;
    35 if button==1:
    36 
    37      qukuan();
    38 else:
    39     cunkuan();
    
    

     ##

    ###########################装饰器装饰有参数的函数
     1 #装饰器装饰有参数的函数
     2 #按照下面的写法看似没有问题,实际会返回错误:inner() takes 0 positional arguments but 1 was given
     3 #看报错原因就知道,inner()函数多了一个参数。大家一定要注意一点,因为装饰器函数的返回值是inner,可以看成inner()==aa()
     4 #所以inner()的输入、输出的类型!必须和aa一模一样!!!!!!!!!
     5 def zhuangshi(func):
     6     def inner():
     7         func();
     8         print('装饰一下');
     9     return inner;
    10 @zhuangshi
    11 def aa(a):
    12     print('哈哈',a);
    13 
    14 aa(2);

    ##因此把上面代码修改如下(注意红字部分)

     1 def zhuangshi(func):
     2     def inner(str):
     3         func(str);
     4         print('装饰一下');
     5     return inner;
     6 @zhuangshi
     7 def aa(a):
     8     print('哈哈',a);
     9 
    10 aa(2);
    
    
    ###########################装饰器装饰有返回值(return)的函数
    1、因为inner函数不会有return
    2、但是重点是inner()的返回值,必须必须要跟被装饰函数一样
    3、所以原函数有return返回值
    4、所以inner函数也要有返回值
     
  • 相关阅读:
    WinForm事件中的Object sender和EventArgs e参数
    Day 25:Python 模块 collections 3 个常用类
    Day 23:Python 中的一些高频面试题及解答小记
    Day 22:Python 迭代器和生成器小记
    Day 21:Python 多线程和协程
    Day 20:python中几个常用的内置函数
    Day 19:Python 函数五类参数
    遍历容器auto方法
    JS鼠标提示框效果
    数据库(二)
  • 原文地址:https://www.cnblogs.com/shenyexiaoqingxin/p/10417195.html
Copyright © 2020-2023  润新知