前提必备

不急着进入正题,在前面函数作用域那一章介绍了闭包,全局变量局部变量,这里再看几个简单的闭包案例:

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)—>利用经典案例解析装饰器概念的更多相关文章

  1. 洗礼灵魂,修炼python(43)--巩固篇—经典类/新式类

    经典类 1.什么是经典类 就是在使用class关键词时,括号内不添加object类的就叫经典类,前面的博文里是绝对解析过的,所以你应该知道,经典类现在已经仅存在于python2了,因为python3不 ...

  2. 洗礼灵魂,修炼python(15)--列表进阶话题—>列表解析/列表生成器

    是的,我是想到什么知识点就说什么,没有固定的主题,我的标题都是在写完博客再给的.本篇博文说说列表进阶话题.其实列表应该是比较熟悉的了,而毫不夸张的说,在实际的开发中,列表也是使用的最多的,以后你会体会 ...

  3. 洗礼灵魂,修炼python(30)--装饰器(2)—>装饰器总结+进阶使用

    在上一篇博文的经典案例中,我想你应该对装饰器有很好的了解了,不过光有那些还不够真的,还需要总结和进阶一下,所以本篇博文解析装饰器进阶. 装饰器 1.什么是装饰器? 个人理解:装饰器又叫语法糖,指的是对 ...

  4. 洗礼灵魂,修炼python(85)-- 知识拾遗篇 —— 深度剖析让人幽怨的编码

    编码 这篇博文的主题是,编码问题,老生常谈的问题了对吧?从我这一套的文章来看,前面已经提到好多次编码问题了,的确这个确实很重要,这可是难道了很多能人异士的,当你以为你学懂了,在研究爬虫时你发现你错了, ...

  5. 洗礼灵魂,修炼python(69)--爬虫篇—番外篇之feedparser模块

    feedparser模块 1.简介 feedparser是一个Python的Feed解析库,可以处理RSS ,CDF,Atom .使用它我们可从任何 RSS 或 Atom 订阅源得到标题.链接和文章的 ...

  6. 洗礼灵魂,修炼python(71)--爬虫篇—【转载】xpath/lxml模块,爬虫精髓讲解

    Xpath,lxml模块用法 转载的原因和前面的一样,我写的没别人写的好,所以我也不浪费时间了,直接转载这位崔庆才大佬的 原帖链接:传送门 以下为转载内容: --------------------- ...

  7. 洗礼灵魂,修炼python(52)--爬虫篇—【转载】爬虫工具列表

    与爬虫相关的常用模块列表. 原文出处:传送门链接 网络 通用 urllib -网络库(stdlib). requests -网络库. grab – 网络库(基于pycurl). pycurl – 网络 ...

  8. python学习之路-4 内置函数和装饰器

    本篇涉及内容 内置函数 装饰器 内置函数 callable()   判断对象是否可以被调用,返回一个布尔值 1 2 3 4 5 6 7 8 9 10 11 num = 10 print(callabl ...

  9. Python之路第四天,基础(4)-装饰器,迭代器,生成器

    装饰器 装饰器(decorator)是一种高级Python语法.装饰器可以对一个函数.方法或者类进行加工.在Python中,我们有多种方法对函数和类进行加工,比如在Python闭包中,我们见到函数对象 ...

随机推荐

  1. 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 ...

  2. 离不开的微服务架构,脱不开的RPC细节

    服务化有什么好处? 服务化的一个好处就是,不限定服务的提供方使用什么技术选型,能够实现大公司跨团队的技术解耦,如下图所示: 服务A:欧洲团队维护,技术背景是Java 服务B:美洲团队维护,用C++实现 ...

  3. Java读取Properties的几种方法

    本文转载自:http://blog.csdn.net/chjttony/article/details/5927613 每次用完每次忘相对与绝对...

  4. centos7 部署YApi

    =============================================== 2018/6/5_第2次修改                       ccb_warlock 更新说 ...

  5. 122. 买卖股票的最佳时机 II-leetcode

    题目: 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格. 设计一个算法来计算你所能获取的最大利润.你可以尽可能地完成更多的交易(多次买卖一支股票). 注意:你不能同时参与多笔交易(你必 ...

  6. Spring Boot + Spring Cloud 构建微服务系统(一):服务注册和发现(Consul)

    使用Consul提供注册和发现服务 什么是 Consul Consul 是 HashiCorp 公司推出的开源工具,用于实现分布式系统的服务发现与配置.与其它分布式服务注册与发现的方案,Consul ...

  7. Vue + Element UI 实现权限管理系统 前端篇(十):动态加载菜单

    动态加载菜单 之前我们的导航树都是写死在页面里的,而实际应用中是需要从后台服务器获取菜单数据之后动态生成的. 我们在这里就用上一篇准备好的数据格式Mock出模拟数据,然后动态生成我们的导航菜单. 接口 ...

  8. QMessageBox的使用

    /** 使用非静态API,属性设置API **/ QMessageBox msgBox; msgBox.setWindowTitle("Note");/** 设置标题 **/ ms ...

  9. ThreadLocalMap里Entry为何声明为WeakReference?

    Java里,每个线程都有自己的ThreadLocalMap,里边存着自己私有的对象.Map的Entry里,key为ThreadLocal对象,value即为私有对象T.在spring MVC中,常用T ...

  10. SSH原理和应用

    SSH(Secure SHell)是为远程登录, 远程通信等设计的安全通信协议, 由芬兰研究员于1995年提出,其目的是用于替代非安全的Telnet.rsh.rexec等不安全的远程Shell协议. ...