当前位置:   article > 正文

Python入门知识点 10--闭包与装饰器

Python入门知识点 10--闭包与装饰器

一、直接与间接程序开发潜规则

生活中:
    有台电脑,他的硬盘空间不够了,里面的资料我不能动,也不能删,咋办
    1.加装硬盘--直接解决--前提是我的电脑能加装
    2.插个u盘--间接解决-->没有特别的要求,比较灵活
    
开发潜规则:
    代码拓展-->开放-->可以加功能
    源码修改-->封闭-->不能随便改源代码
    
一个程序做好之后,一般是不会随意删改里面的函数代码的
如果改了源代码,导致程序出bug了,修改起来很麻烦,所以一般不会再改源码
还有就是随便就能修改,那这样的代码安全性很差
所以有一个要求,就是对于写好的一些代码不应该再随便修改它

那如果要给这个函数加功能,那我们的做法就是可以
    不修改函数的源代码,通过间接的方式去修改
    
间接修改--化妆--通过装饰器
直接修改--整容--修改源代码

二、初识闭包函数

闭:封闭,指的就是一个嵌套函数的内层函数

包:用内层函数,来操作外层函数得到的数据

作用:间接修改数据,保护私有数据不被轻易修改

闭包函数必备的条件:

  1、必须是一个嵌套函数
  2、内层函数必须操作外层函数数据(这个数据可以是一个变量或者是参数)
  3、外层函数必须返回内层函数

闭包可以说就是为了装饰器而生的,单独写闭包意义不大,一般都是配合装饰器来使用

闭包格式:
    def 外层函数():
        def 内层函数():
            操作外层函数的数据
        return 内函数名   #不需要加括号

  1. #普通函数
  2. #有个打工仔小赵,钱包里刚开始是0元
  3. money=0
  4. def work(): #定义工作的函数
  5. global money
  6. money+=100
  7. work() #工作一天
  8. print(money) #100元
  9. work() #工作二天
  10. print(money) #200元
  11. work() #工作三天
  12. print(money) #300元
  13. money=0 #天有不测风云,钱包被抢了
  14. print(money) #0元
  15. # #重新工作
  16. work()
  17. print(money) #上面的情况 因为没有封闭很容易被修改
  18. #闭包 操作外层函数的变量
  19. def person():
  20. money = 0
  21. def work_1():
  22. nonlocal money
  23. money+=150
  24. print(money)
  25. return work_1 #返回内层函数名 不需要现在调用
  26. res=person() #res 等同于 work_1
  27. res() ##res() 等同于 work_1()
  28. res()
  29. money=0
  30. res() #450 并没有修改 因为我们这里是封闭的,闭包的作用就是保护私有数据不被轻易修改

检测闭包函数的使用:内函数名.__closure__

print(res.__closure__)  #如果打印出来cell,则是闭包,如果是None,就不是闭包函数

#闭包 操作外层函数的参数
#process 是一个 可以给<函数>加功能的函数,给需要加功能的函数加一句话
#a只是形参,只是个名字,它是给要加功能的函数占位置,后面会接收一个函数作为实参传入进来

  1. def process(a):
  2. def product():
  3. a() #a本质是一个函数,先调用你传进来的函数,确保原来的函数功能可以使用
  4. print('我加了个鸡爪')
  5. return product
  6. def food():
  7. print('我是螺蛳粉')
  8. def rice():
  9. print('我是一碗大米饭')
  10. food=process(food) #用加了功能的函数,重新赋值给原函数,原函数才做到了加功能
  11. food()
  12. rice=process(rice)
  13. rice()

三、初识装饰器(wrapper)

装饰器:本质就是一个函数,是一个特殊的闭包

添加装饰器的前提:

1.要有闭包函数的存在

2.要有被装饰的函数

装饰器的作用就是不修改函数源代码/参数的前提下,给一个或者多个函数添加功能
优点:
    1.通过间接的方式,保护私有数据不被轻易改变,给函数加功能,会更安全
    2.可以给一个/多个函数增加功能,更方便

私聊客服/购买/加入购物车 --> 功能函数
都需要先登录,判断是否登录是必须的,如果登录了才可以正常使用,否则转到登录界面

私聊客服:
    判断是否登录
    .......
    
购买:
    判断是否登录
    .......
    
专门写个工具函数,作用就是给每个函数增加一个登录功能-->判断是否登录装饰器--给一个/多个函数添加功能,反复使用,-->写一个装饰器,功能就是判断是否登录,然后把装饰器加在其他函数里就可以了

上面的加鸡爪的函数,就属于一个装饰器函数
    1.process是一个工具函数 ,作用是给一个函数加功能
    2.要给函数加功能,就得接收函数,a就是函数的形,给要加功能的函数先占好位置
    3.接收好函数之后,先调用传进来的函数,确保它原来的功能可以正常使用,然后给它加功能
    4.调用函数后,在内层函数里添加对应的功能
    5.返回内层函数(原函数+添加功能)

装饰器的使用方式
    1.函数名=装饰器(函数名) #用加了功能的函数重新赋值给原函数

    2.语法糖
    @装饰器   (外层函数名) #快速给下面的函数添加装饰器的功能

  1. 1、food=process(food)
  2. food()
  3. 2、@process
  4. def noodle():
  5. print('我是一碗面条')
  6. noodle()
  1. def boy(person):
  2. def sport():
  3. person()
  4. print('锻炼出来8块腹肌')
  5. print('长高18cm')
  6. return sport
  7. @boy
  8. def student():
  9. print('我是蔡徐坤')
  10. student()
  11. @boy
  12. def student2():
  13. print('我是斑斑')
  14. student2()

1、带参装饰器

#错误实例
# def girl(person):
#     def make_up():
#         person()
#         print('给小美女化好美美的妆')
#     return make_up
#
# @girl
# def name1(freind):
#     print(f'我是小赵,带了一个朋友{freind}')

# name1('欧雅琪') #报错,因为你这要加功能的函数带了参数,而make_up没有给你的参数准备位置
#也就是如果你要加功能的函数 是有参数的话  是不是也要把参数一起接收过来呢?
#否则函数就不完整了,程序不会给你面子,直接报错

  1. #正确做法
  2. def girl(person):
  3. def make_up(*args,**kwargs): #不管你要加功能的函数传什么类型的参数,传多少参数我都能接收
  4. person(*args,**kwargs)
  5. print('给小美女化好美美的妆')
  6. return make_up
  7. @girl
  8. def name():
  9. print('我是小赵')
  10. name()
  11. @girl
  12. def name1(freind):
  13. print(f'我是小赵,带了一个朋友{freind}')
  14. name1('小张')
  15. @girl
  16. def name2(freind1,freind2):
  17. print(f'我是小赵,带了两个朋友{freind1}{freind2}')
  18. name2('小张','小王')
  1. def people(a):
  2. def thing(*args,**kwargs):
  3. a(*args,**kwargs)
  4. print('准备房间...')
  5. return thing
  6. @people
  7. def fun1():
  8. print('我是单身')
  9. fun1()
  10. @people
  11. def fun2(child1,child2):
  12. print(f'带俩娃,一个是{child1},另一个是{child2}')
  13. fun2('男孩','女孩')

2、装饰器总结

什么情况下会用到装饰器
一个相同功能可能会在很多函数都会用上(登录,收藏,购买),这种情况就可以把函数写为装饰器

特性:在不修改源代码的基础上,给函数加功能

四、print调试

我们一般不用print-->以后做网站后台/小程序后台/爬虫
    1.爬虫的东西一般就是发送请求/保存数据
    2.写后台都是操作数据-->输出内容都是前端的
    
有一个项目有几百行的代码,运行没有报错,但是有的功能没有实现
这时候就可以用print调试
比如代码一共500行,现在有功能没有实现

这个时候就可以在100,200,300,400行各写一个print,运行程序,看程序运行到哪个print,哪个print没有输出,就知道是哪一段代码有问题

输出了第200行的print,前200行没问题,后面的代码有

五、分享几个可以用来学习的博客

https://www.cnblogs.com/huxi/archive/2011/03/01/1967600.html
    
https://www.cnblogs.com/Jerry-Chou/archive/2012/05/23/python-decorator-explain.html
    
https://www.cnblogs.com/cotyb/p/5243252.html
    
https://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html

这篇文章到这就结束了,有什么问题欢迎随时评论或者私信哦~

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/908684
推荐阅读
相关标签
  

闽ICP备14008679号