洗礼灵魂,修炼python(29)--装饰器(1)—>利用经典案例解析装饰器概念
前提必备
不急着进入正题,在前面函数作用域那一章介绍了闭包,全局变量局部变量,这里再看几个简单的闭包案例:
1):不带参数
注意:
1.这里的name属性是每个函数都有的,可以反馈函数名
2.temp()是调用函数的意思,如果直接temp只是一个函数对象,并且打印出这个函数的内存地址
2):外层函数带参数
3):内外层函数都带参数
如果希望让内层函数修改外层函数的参数并返回呢?前面说过的,这样会引起异常,为什么会引起异常以及怎么解决在函数作用域那一章说过的,不记得的自己回头看下。在这里直接略过,本篇文章不需要此知识点。
能掌握以上的与函数有关的代码原理,才能方便进入下面的正题。
那么本篇博文的主旨是装饰器,什么是装饰器,怎么用装饰器,装饰器能干什么?这些问题通过下面的经典例子都可以得到解答
案例
首先说明,我是借用了其经典例子但没有全部照搬,经典例子的原始出处我已经找不到,因为网上到处都能找到类似的,找到一个发了原帖位置的,点进去网页报错404。如果侵权,请原作者联系我及时删除
案例:有一个大公司,各个基础平台部负责内部应用程序及API的开发,有上百个业务部门负责不同的业务,他们各自调用基础平台部提供的不同函数处理自己的业务
如下:
def bumen1(): print("部门1数据......") def bumen2(): print("部门2数据......") def bumen3(): print("部门3数据......") ………………………… def bumen100(): print("部门100数据......") #各部门分别调用: bumen1() bumen2() bumen3() bumen100() #结果: 部门1数据...... 部门2数据...... 部门3数据...... …………………… 部门100数据......
问题来了,由于公司目前正处在创业进步期,但是当初基础平台部开发这些函数时,因为各种原因,并没有为函数调用进行安全认证。现在,技术总部老大决定立即弥补这个缺陷。为了解决这个问题,老大找了公司里几个员工:
1)老大叫来了刚入职的技术部小李,小李的方案是:跑上跑下逐个和部门交流沟通,让他们自己在代码里加上认证功能。
然而,当天小李被开除了。
2)老大又从负责运维的小组组长叫来了小王,小王的方案是:写个复杂的shell脚本,勉强实现了功能。
老大还是不太满意,让小王下去忙去了。
3)老大又叫来了技术部老手小张,小张的方案是:只对基础平台的代码进行重构,让各个业务部门无需做任何修改:
def authentication(): #认证函数 if True: #(判断代码块,作伪代码意思一下,因为公司有哪些部门怎么认证没有已知条件具体不好说,没有展开具体的判断语句) print("认证成功") return 1 while authentication(): def bumen1(): print("部门1数据......") def bumen2(): print("部门2数据......") def bumen3(): print("部门3数据......") ………………………… def bumen100(): print("部门100数据......") else: print("认证失败")
老大看了眼睛里露出一丝喜悦,然后拍拍小张的肩膀,让小张忙去了
4)老大又叫来公司里的唯一一个女程序员小红,小红的方案是:其他不变,在每个部门加入一个认证函数:
def authentication(): print("认证成功!") def bumen1(): login() print("部门1数据......") def bumen2(): login() print("部门2数据......") def bumen3(): login() print("部门3数据......")………………………………def bumen100(): login() print("部门100数据......")
老大看完邪魅一笑,看着小红可爱的脸蛋,慢慢靠近小红,小红开始心跳加速,小脸微红,略显紧张,但还是没有立即起身起来,等着老大的发号施令,老大站定,说:你的代码大体没问题,功能也实现了,但是写代码要遵循开放封闭原则,虽然这个原则主要是针对面向对象开发,但是也适用于很多实际的开发中。开放封闭原则规定已经实现的功能代码内部不允许被修改,但外部可以被扩展,即封闭已实现的功能代码块,开放对扩展开放。如果将开放封闭原则应用在上述需求中,那么就不允许在函数bumen1,bumen2,bumen3……bumen100的内部进行代码修改的。
小红恍然大悟并若有所思,过了一会儿,小红对老大说:“还是大哥厉害,可以教教我怎么改吗?”,老大爽快的答应了,嘴角向上一扬说:“今晚去我家详解介绍吧”。小红抿嘴一笑微微点头同意了。
晚上在老大家里,老大写下这段参考代码:
#/usr/bin/env python #coding:utf-8 def outer(func): def inner(): print("认证成功!") return func() return inner @outer def bumen1(): print("部门1数据......") @outer def bumen2(): print("业务部门2数据......") @outer def bumen3(): print("部门3数据......") @outer def bumen100(): print("部门100数据......") #各部门分别调用 bumen1() bumen2() bumen3() bumen100() #结果: 认证成功! 部门1数据..... 认证成功! 部门2数据..... 认证成功! 部门3数据..... 认证成功! 部门100数据.....
小红看了下,有些不解道:为什么要用两层函数?一层不行吗?小红写下只有一层的代码:
#/usr/bin/env python #coding:utf-8 def outer(func): print("认证成功!") return func() @outer def bumen1(): print("部门1数据......") @outer def bumen2(): print("业务部门2数据......") @outer def bumen3(): print("部门3数据......") @outer def bumen100(): print("部门100数据......") #各部门分别调用 bumen1() bumen2() bumen3() bumen100()
结果:
发现结果是运行了,但是报错了,小红问老大什么情况,老大啥都没说,把代码删除了一点,让小红运行看:
#/usr/bin/env python #coding:utf-8 def outer(func): print("认证成功!") return func() @outer def bumen1(): print("部门1数据......") @outer def bumen2(): print("业务部门2数据......") @outer def bumen3(): print("部门3数据......") @outer def bumen100(): print("部门100数据......")
结果:
小红发现,各个部门的函数还没调用呢就已经运行了,小红心想,这样如果运用于实际开发要出事啊,各个部门都还没开工,我一个代码就直接帮他们搞定了,没搞错还好,万一搞错了,我岂不背大锅啊?这绝对不行。小红又把老大给的代码删除了调用函数的那几行试了下:
发现利用老大的代码删除了那几行调用函数的代码,啥都不会运行,这才符合逻辑的,小红开始真正的佩服老大。小红继续研究代码,过了一会儿,她想,外层函数可以认证吗?试试看:
果然又是,各个部门的函数还没调用就开始有反馈信息了,这肯定是不行,老大在一旁看了下,说道:“你这个想法不错。其实代码中如果有装饰器的话,代码会优先运行装饰器函数,所以当代码运行时,装饰器已经蓄势待发等着被装饰的函数调用并装饰它了,同时,如果有多个装饰器,装饰器之间优先级由上而下”
小红总结道:程序默认是由上而下运行,而在程序中如果有装饰器,装饰器的优先级比一般定义的函数的优先级高,同时,如果有多个装饰器,默认装饰器之间优先级由上而下
小红继续看代码,突然又想到一个问题,这样的代码,虽然暂时没问题,但是如果不在认证函数那里调用函数只是返回一下原函数对象,让原函数自己调用呢?因为实际开发中,不可能只是作为一个print就完事了的
小红把装饰函数返回函数的括号去掉了,结果:
这个结果有点小红出乎意料,发现各个部门的函数不工作了,小红试着print一下部门1的函数
原来被装饰函数在调用时因为被装饰后成了一个函数对象,没有调用了。结果:(只截取了部分,代码没变)
加上调用后:(代码一样,只截取结果)
但这样,岂不是每个部门调用时都要还要多加括号来调用一次?小红不解了,把这个情况告诉刚洗完澡出来的老大,老大看了下,想了下说:“之前我给的代码只是简单的测试,如果各个部门不传参数,是没问题的,如果各个部门要传入参数,确实是需要你这样改代码,不过,原理也一样,直接在装饰函数那里改下就行了":
#/usr/bin/env python #coding:utf-8 def authentication(func): def inner(args): print("认证成功!") return func(args) return inner @authentication def bumen1(num): print("部门1数据......") return '部门'+str(num) @authentication def bumen2(num): print("部门2数据......") return '部门'+str(num) @authentication def bumen3(num): print("部门3数据......") return '部门'+str(num) @authentication def bumen100(num): print("部门100数据......") return '部门'+str(num) #各部门分别调用 print(bumen1(1)) print(bumen2(2)) print(bumen3(3)) print(bumen100(100))
结果:
小红看后拍手叫好,继续研究这个带参数的代码,小红确实有程序员的素质,遇到问题爱思考,小红又想如果直接返回原函数呢?不调用看看:
果然如此啊,小红越发钦佩老大,觉得今晚来老大家里来对了,然后………………(未完待续,此处省略两万个字 /滑稽)
好的,我借用经典案列修改的的例子已经结束。是的,没错案例中老大用的就是—装饰器,相信看完这个例子,你已经对装饰器有了很不错的理解了。
下一篇讲解装饰器进阶篇
由于有朋友跟我提意见说,一篇博文太长看得累,所以以后如果有知识点太多的我尽量分成两份或者三份写
洗礼灵魂,修炼python(29)--装饰器(1)—>利用经典案例解析装饰器概念的更多相关文章
- 洗礼灵魂,修炼python(43)--巩固篇—经典类/新式类
经典类 1.什么是经典类 就是在使用class关键词时,括号内不添加object类的就叫经典类,前面的博文里是绝对解析过的,所以你应该知道,经典类现在已经仅存在于python2了,因为python3不 ...
- 洗礼灵魂,修炼python(15)--列表进阶话题—>列表解析/列表生成器
是的,我是想到什么知识点就说什么,没有固定的主题,我的标题都是在写完博客再给的.本篇博文说说列表进阶话题.其实列表应该是比较熟悉的了,而毫不夸张的说,在实际的开发中,列表也是使用的最多的,以后你会体会 ...
- 洗礼灵魂,修炼python(30)--装饰器(2)—>装饰器总结+进阶使用
在上一篇博文的经典案例中,我想你应该对装饰器有很好的了解了,不过光有那些还不够真的,还需要总结和进阶一下,所以本篇博文解析装饰器进阶. 装饰器 1.什么是装饰器? 个人理解:装饰器又叫语法糖,指的是对 ...
- 洗礼灵魂,修炼python(85)-- 知识拾遗篇 —— 深度剖析让人幽怨的编码
编码 这篇博文的主题是,编码问题,老生常谈的问题了对吧?从我这一套的文章来看,前面已经提到好多次编码问题了,的确这个确实很重要,这可是难道了很多能人异士的,当你以为你学懂了,在研究爬虫时你发现你错了, ...
- 洗礼灵魂,修炼python(69)--爬虫篇—番外篇之feedparser模块
feedparser模块 1.简介 feedparser是一个Python的Feed解析库,可以处理RSS ,CDF,Atom .使用它我们可从任何 RSS 或 Atom 订阅源得到标题.链接和文章的 ...
- 洗礼灵魂,修炼python(71)--爬虫篇—【转载】xpath/lxml模块,爬虫精髓讲解
Xpath,lxml模块用法 转载的原因和前面的一样,我写的没别人写的好,所以我也不浪费时间了,直接转载这位崔庆才大佬的 原帖链接:传送门 以下为转载内容: --------------------- ...
- 洗礼灵魂,修炼python(52)--爬虫篇—【转载】爬虫工具列表
与爬虫相关的常用模块列表. 原文出处:传送门链接 网络 通用 urllib -网络库(stdlib). requests -网络库. grab – 网络库(基于pycurl). pycurl – 网络 ...
- python学习之路-4 内置函数和装饰器
本篇涉及内容 内置函数 装饰器 内置函数 callable() 判断对象是否可以被调用,返回一个布尔值 1 2 3 4 5 6 7 8 9 10 11 num = 10 print(callabl ...
- Python之路第四天,基础(4)-装饰器,迭代器,生成器
装饰器 装饰器(decorator)是一种高级Python语法.装饰器可以对一个函数.方法或者类进行加工.在Python中,我们有多种方法对函数和类进行加工,比如在Python闭包中,我们见到函数对象 ...
随机推荐
- Spark之submit任务时的Initial job has not accepted any resources; check your cluster UI to ensure that workers are registered and have sufficient memory
Spark submit任务到Spark集群时,会出现如下异常: Exception 1:Initial job has not accepted any resources; check your ...
- 离不开的微服务架构,脱不开的RPC细节
服务化有什么好处? 服务化的一个好处就是,不限定服务的提供方使用什么技术选型,能够实现大公司跨团队的技术解耦,如下图所示: 服务A:欧洲团队维护,技术背景是Java 服务B:美洲团队维护,用C++实现 ...
- Java读取Properties的几种方法
本文转载自:http://blog.csdn.net/chjttony/article/details/5927613 每次用完每次忘相对与绝对...
- centos7 部署YApi
=============================================== 2018/6/5_第2次修改 ccb_warlock 更新说 ...
- 122. 买卖股票的最佳时机 II-leetcode
题目: 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格. 设计一个算法来计算你所能获取的最大利润.你可以尽可能地完成更多的交易(多次买卖一支股票). 注意:你不能同时参与多笔交易(你必 ...
- Spring Boot + Spring Cloud 构建微服务系统(一):服务注册和发现(Consul)
使用Consul提供注册和发现服务 什么是 Consul Consul 是 HashiCorp 公司推出的开源工具,用于实现分布式系统的服务发现与配置.与其它分布式服务注册与发现的方案,Consul ...
- Vue + Element UI 实现权限管理系统 前端篇(十):动态加载菜单
动态加载菜单 之前我们的导航树都是写死在页面里的,而实际应用中是需要从后台服务器获取菜单数据之后动态生成的. 我们在这里就用上一篇准备好的数据格式Mock出模拟数据,然后动态生成我们的导航菜单. 接口 ...
- QMessageBox的使用
/** 使用非静态API,属性设置API **/ QMessageBox msgBox; msgBox.setWindowTitle("Note");/** 设置标题 **/ ms ...
- ThreadLocalMap里Entry为何声明为WeakReference?
Java里,每个线程都有自己的ThreadLocalMap,里边存着自己私有的对象.Map的Entry里,key为ThreadLocal对象,value即为私有对象T.在spring MVC中,常用T ...
- SSH原理和应用
SSH(Secure SHell)是为远程登录, 远程通信等设计的安全通信协议, 由芬兰研究员于1995年提出,其目的是用于替代非安全的Telnet.rsh.rexec等不安全的远程Shell协议. ...