1、首先,有个原来写好的函数,完成一定的功能,比如下面的,就打印一句话(某程序被调用)。简单点,容易帮我们想清楚程序是怎么执行的。

 '''
原函数
'''
def fun1():
print("fun1 is called.") fun1()

结果:

2、然后,有个需求,要在原来的函数上加个功能,我们简单点,就再打印一句话吧(某新功能加入)。

2.1 不懂装饰器,就直白点吧,加一个fun2

 '''
在原来的函数上加个功能
再打印一句话吧(某新功能加入)。
'''
def fun2():
print("new fun is called") '''
原函数
打印一句话(某程序被调用),
'''
def fun1():
fun2()
print("fun1 is called.") fun1()

结果:

这样子,结果是我们想要的,先执行新功能的程序,再执行原功能的程序,但是有个问题,原来的程序中加入了新的代码,示例中的13行。

写程序有个原则,叫封闭,就是原来跑得好好的代码不要再去改它,免得改来改去得再出问题。所以,我们得改。

2.2 不修改源代码,我们把原函数名字作为参数传给新功能的函数,先跑新功能,完了再掉用作为参数传进去的原功能

 '''
在原来的函数上加个功能
再打印一句话吧(某新功能加入)。
'''
def fun2(funname):
print("new fun is called")
funname() '''
原函数
打印一句话(某程序被调用),
'''
def fun1():
print("fun1 is called.") fun2(fun1)

结果:

也是我们要的结果。然后新问题来了,这种方式,可不是原来直接调用fun1(),那么程序中所有用到fun1()的地方都得改成fun2(fun1),如果需要实现对就功能进行加强的地方很多,可以想象,你得找到所有的地方进行修改,程序大了,可不能这么干,万一漏了呢?我们还得改。

2.3 不改源代码,不改调用方式

把原来的程序在新程序中返回,然后再赋值给fun1,这样执行会是什么结果呢?

 '''
在原来的函数上加个功能
再打印一句话吧(某新功能加入)。
'''
def fun2(funname):
print("new fun is called")
return funname '''
原函数
打印一句话(某程序被调用),
'''
def fun1():
print("fun1 is called.") fun1=fun2(fun1) fun1()

结果:

在这个程序里,调用fun1()可以获得和原来一样的结果,但是,这里有个问题,“new fun is called”是在16行的时候,运行fun2时出来的,“fun1 is called”是在18行运行fun1时出来的,也就是说这个程序实际上并没有将fun1和fun2关联起来,它并没有在fun1()调用的时候同时实现新旧两个功能,它和以下代码是一样的

 def fun2():
print("new fun is called")
return
def fun1():
print("fun1 is called.")
fun2()
fun1()

这就没有装饰的意思了
2.4 不改源代码,不改调用方式,一次调用执行实现新旧两个功能

 '''
在原来的函数上加个功能
再打印一句话吧(某新功能加入)。
'''
def fun2(funname):
def inner():
print("new fun is called")
funname()
return inner '''
原函数
打印一句话(某程序被调用),
'''
def fun1():
print("fun1 is called.") fun1=fun2(fun1) fun1()

在这个代码里,fun1作为参数传给fun2,在fun2中定义了一个函数,在这个嵌套定义的函数中实现了新功能,那么fun2干嘛呢?它只是将这个新功能的地址作为返回值返回。我们拿到这个返回值,重新赋值给fun1,那么再调用fun1的时候,实际上是调用的fun2中定义的新功能函数。
结果:

我们可以通过debug运行,给每行打上断点,就能知道最终的结果是在运行到21行的时候一起出来的。

2.5 在以上基础上,可以看到旧功能是在fun1中实现的,新功能是在fun2中实现的,调用的还是fun1,多了一句话,即19行,传参+复制,会不会搞不清楚,于是,简写一下

 '''
在原来的函数上加个功能
再打印一句话吧(某新功能加入)。
'''
def fun2(funname):
def inner():
print("new fun is called")
funname()
return inner '''
原函数
打印一句话(某程序被调用),
'''
@fun2
def fun1():
print("fun1 is called.") fun1()

将@fun2写在fun1之前,就表示fun2写了新功能,它是在fun1的基础上来的,把fun1妆点了一下门面,有点加强了--装饰器这个名字很贴切的。

2.6 函数的定义是为了重复调用,可以少写代码,现在我们有fun2(新功能),可以想象,可能有很多其他的fun**(旧功能)需要妆点,如果原来的fun**本身带参数,那么就会报错。

 '''
在原来的函数上加个功能
再打印一句话吧(某新功能加入)。
'''
def fun2(funname):
def inner():
print("new fun is called")
funname()
return inner '''
原函数
打印一句话(某程序被调用),
'''
@fun2
def fun1():
print("fun1 is called.") @fun2
def fun3(arg1):
print("fun3 welcome: %s "%arg1) fun1()
fun3("susen")

结果:

所以,我们需要用非固定参数来解决这个问题。在装饰器的inner函数用非固定参数*args,**kwargs,这样,不管原来的函数有多少参数,都可以调用了。

 '''
在原来的函数上加个功能
再打印一句话吧(某新功能加入)。
'''
def fun2(funname):
def inner(*args,**kwargs):
print("new fun is called")
funname(*args,**kwargs)
return inner '''
原函数
打印一句话(某程序被调用),
'''
@fun2
def fun1():
print("fun1 is called.") @fun2
def fun3(arg1):
print("fun3 welcome: %s "%arg1) fun1()
fun3("susen")

结果:

3、总结

按照上面一步步得来,应该能明白装饰器是怎么工作的了,基础知识有:非固定参数传参、函数名实际上也是一个变量(内存地址)、嵌套函数。明白以后,之后写代码就套用格式就完了。

python--对于装饰器的理解的更多相关文章

  1. 转发对python装饰器的理解

    [Python] 对 Python 装饰器的理解的一些心得分享出来给大家参考   原文  http://blog.csdn.net/sxw3718401/article/details/3951958 ...

  2. 理解Python中的装饰器//这篇文章将python的装饰器来龙去脉说的很清楚,故转过来存档

    转自:http://www.cnblogs.com/rollenholt/archive/2012/05/02/2479833.html 这篇文章将python的装饰器来龙去脉说的很清楚,故转过来存档 ...

  3. python中闭包和装饰器的理解(关于python中闭包和装饰器解释最好的文章)

    转载:http://python.jobbole.com/81683/ 呵呵!作为一名教python的老师,我发现学生们基本上一开始很难搞定python的装饰器,也许因为装饰器确实很难懂.搞定装饰器需 ...

  4. Python(三)对装饰器的理解

    装饰器是 Python 的一个重要部分,也是比较难理解和使用好的部分.下面对装饰器做一下简单整理 1. 前言 装饰器实际上是应用了设计模式里,装饰器模式的思想: 在不概念原有结构的情况下,添加新的功能 ...

  5. Python - 关于带参数的装饰器的理解

    [原创]转载请注明作者Johnthegreat和本文链接 关于装饰器的理解,特别像<盗梦空间>中的进入梦境和从梦境出来的过程,一层一层的深入梦境,然后又一层一层的返回,被带入梦境的是被装饰 ...

  6. 【转】详解Python的装饰器

    原文链接:http://python.jobbole.com/86717/ Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现 ...

  7. python基础—装饰器

    python基础-装饰器 定义:一个函数,可以接受一个函数作为参数,对该函数进行一些包装,不改变函数的本身. def foo(): return 123 a=foo(); b=foo; print(a ...

  8. 详解Python的装饰器

    Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现了say_hello()和say_goodbye()两个函数. def sa ...

  9. 关于python的装饰器(初解)

    在python中,装饰器(decorator)是一个主要的函数,在工作中,有了装饰器简直如虎添翼,许多公司面试题也会考装饰器,而装饰器的意思又很难让人理解. python中,装饰器是一个帮函数动态增加 ...

  10. 【转】Python之装饰器

    [转]Python之装饰器 本节内容 必要知识回顾 情景模拟 装饰器的概念及实现原理 回马枪(带参数的装饰器) 一. 必要知识回顾 在开始说装饰器之前,需要大家熟悉之前说过的相关知识点: 函数即“变量 ...

随机推荐

  1. Selenium+java操作浏览器cookies

    描述:登录CSDN,将登录信息cookies保存到文件,再次打开网页时,直接利用文件中的数据登录. 1. 获取cookies并保存到文件 步骤: ① 打开CSDN的登录界面: ② 填写用户名和密码: ...

  2. Python 实现排序算法

    排序算法 下面算法均是使用Python实现: 插入排序 原理:循环一次就移动一次元素到数组中正确的位置,通常使用在长度较小的数组的情况以及作为其它复杂排序算法的一部分,比如mergesort或quic ...

  3. Linux - 简明Shell编程04 - 判断语句(If)

    脚本地址 https://github.com/anliven/L-Shell/tree/master/Shell-Basics 示例脚本及注释 #!/bin/bash var=$1 # 将脚本的第一 ...

  4. this和super关键字在构造器中放置第一行的原因

    this()在第一行的原因就是: 为保证父类对象初始化的唯一性. 我们假设一种情况, 类B是类A的子类, 如果this()可以在构造函数的任意行使用, 那么会出现什么情况呢? 首先程序运行到构造函数B ...

  5. RMAN备份介质的移动与再恢复测试 [ catalog start with ‘dir’ ]

    --RMAN备份介质的移动与再恢复测试 ---------------------------------------------------------2013/09/21   由于目前生产环境中没 ...

  6. 【javascript】详解javascript闭包 — 大家准备好瓜子,我要开始讲故事啦~~

    前言: 在这篇文章里,我将对那些在各种有关闭包的资料中频繁出现,但却又千篇一律,且暧昧模糊得让人难以理解的表述,做一次自己的解读.或者说是对“红宝书”的<函数表达式/闭包>的那一章节所写的 ...

  7. javaweb中重定向和请求转发(response.sendRedirect()和request.getRequestDispatcher(rul).forward(request,response)))的区别

    先来两张图,方便理解: 可以看出,重定向时,是服务器向游览器重新发送了一个response命令,让游览器再次向url2发送请求,以获取url2的资源 而请求转发时,类似于是服务器自己向自己发了一个跳转 ...

  8. windows7下VirtualBox COM获取对象失败

    一.问题 今天在windows7系统下安装virtualbox报错:VirtualBox COM获取对象失败,应用程序将被中断.上网查了下,发现了解决办法. 环境:windows7.VirtualBo ...

  9. 迈向angularjs2系列(8):angular cli和angular2种子项目

    文章目录 1.angular cli快速搭建项目 2.angular2-seed 3.手动配置 题外话:如何更好的阅读本篇文章 一: angular cli的安装 Angular-cli(命令行界面, ...

  10. 流畅python学习笔记:第十九章:动态属性和特性

    首先来看一个json文件的读取.书中给出了一个json样例.该json文件有700多K,数据量充足,适合本章的例子.文件的具体内容可以在http://www.oreilly.com/pub/sc/os ...