装饰器是什么呢?

我们先来打一个比方,我写了一个python的插件,提供给用户使用,但是在使用的过程中我添加了一些功能,可是又不希望用户改变调用的方式,那么该怎么办呢?

这个时候就用到了装饰器。装饰器的原理是什么?我们接下来就一步一步看过来!

假如我们有一个home函数如下:

 def home():
print 'this is the home page!'

而我们希望用户在访问home函数之前先验证一下权限,那么在不改变用户调用方法的情况下,就需要在home中调用一个login函数,就像这样:

def login(usr):
if usr == 'xs':
return True
def home():
result = login()
if result:
print 'this is the home page!'

这样可以实现我们的需求,但是我们看到home的代码发生了很大的变化,所有的代码都要被包裹在一个if语句中,并且要进行缩进,这往往不是我们希望看到的。那么我们还可以怎么做呢?
首先我们看一个小例子:

def home():
print 'this is the home page!' print home 输出:<function home at 0x000000000219C978>

我们定义了一个home函数,但是并不使用home()调用它,而是让程序打印出home方法的地址。

那么我们再看这段代码:

def login(usr):
if usr == 'xs':
return True
def wrapper(funcname):
if login('xs'):
return funcname
def home():
print 'this is the home page!' home = wrapper(home)
home()
输出的结果:this is the home page!

我们可以看到这段代码的点睛之笔就在这句:“home = wrapper(home)”,我们将home函数的地址当做参数传给了wrapper方法,在wrapper方法中进行验证,验证通过之后再将home方法的地址返回,这个之后再调用home,我们就在没有修改home方法的情况下,调用了home,是不是方便了很多?这就是装饰器的概念!
但是很快我们发现这种方法还是不好,因为用户必须加上那句点睛之笔的代码再执行原本想执行的home方法,于是在python中就规定装饰器可以这样使用:

def login(usr):
if usr == 'xs':
return True def wrapper(funcname):
if login('aaa'):
return funcname @wrapper
def home():
  print 'this is the home page!'
13 home()

看到了吧,我们只需要在home方法上加上一个“@wrapper”,就可以省去原本在home()方法前写的那句话了,这样就方便了很多,而且也没有改变用户的调用方式。
然而,你有没有想过,怎么使用装饰器传递参数?

def home(usr):
print 'this is the home page!'

我们来看看下面的实现方法:

def wrapper1(funcname):
print 'funcname:',funcname
def wrapper2(argv):
if login(argv):
print 'funcname:',funcname
return funcname(argv)
else:
return error
return wrapper2 def home(usr):
print 'this is the home page!'
print 'hello ,',usr home = wrapper1(home)
home('xs')
输出的结果:
funcname: <function home at 0x00000000022CFAC8>
funcname: <function home at 0x00000000022CFAC8>
this is the home page!
hello , xs

解决啦,我们实现了装饰器的传参,那么如果我想传多个参数,不确定的参数可不可以呢?当然可以啦,你就用动态传参就好了呀~~~

看到这里基本上普通青年就够用了。但是作为一个文艺小青年,你愿不愿意用一个晚上的时间,来刨一刨装饰器的祖坟?

先来看多个装饰器的应用。

def wrapper1(func):
def inner():
print 'w1,before'
func()
print 'w1,after'
return inner def wrapper2(func):
def inner():
print 'w2,before'
func()
print 'w2,after'
return inner @wrapper2
@wrapper1
def foo():
print 'foo' foo() 运行结果:
w2,before
w1,before
foo
w1,after
w2,after

从上面这个例子我们可以看出,装饰器就像是一个俄罗斯套娃,把被装饰的方法当成最小的一个娃娃,封装在最内层,外面一层一层的嵌套装饰器。

接下来再看一个装饰器传递函数参数的例子:

def Before(request):
print 'before' def After(request):
print 'after' def Filter(before_func,after_func):
def outer(main_func):
def wrapper(request):
before_result = before_func(request)
if(before_result != None):
return before_result;
main_result = main_func(request)
if(main_result != None):
return main_result;
after_result = after_func(request)
if(after_result != None):
return after_result;
return wrapper
return outer @Filter(Before, After)
def Index(request):
print 'index' Index('example') 先上结果:
before
index
after

首先,index里我只是随便传了一个参数,并没有什么实际的意义,不要被迷惑了。接下来看看这段代码的执行过程:

看上面这张图,先来统一解释一下,代码前面的数字是python在执行Index之前做的事情,它将这段代码中函数的地址写入内存,方便之后在调用中可以一下子找到。

在装饰器这里有点绕,来来回回了好几次,我们解释一下从第3步往后的步骤,首先是在第3步这里,解释器发现了这个函数,并把它放进了内存里,然后第4步又读到了一个装饰器,它就从内存里找到装饰器的地址返回到了第5步这个装饰器的位置。继续往下读,第6步它又把发现了一个outer函数,于是欢欢喜喜的把outer函数的地址放进了内存里,然后就停止了,因为它很清楚它不是来执行outer的,所以它调过了这个函数并顺序执行了这个函数外面的第一句话:第7步,return outer。这个时候解释器发现这不就是刚刚记下了地址的那个方法么?它就又回来了之前的地址,找到了outer函数。。。就是这样,直到执行到第10步return wrapper,这里我没有写,其实它也是兴冲冲的回到了家wrapper方法那里的,但是它发现下面已经没有它需要记录地址的函数了。所以它把最后的这个wrapper函数的地址返回给了装饰器,也就是装饰器下面的index方法。

这个时候,好巧不巧的,我们在程序中调用了这个index方法,那么解释器就把我们领到wrapper那里开始执行了,在wrapper里我们可以使用外层函数传过来的方法参数Before和After,这其实就是装饰器参数祖坟里的秘密了。不要问我17\21\25步后面为什么没有执行,因为我们的函数都没有返回值呀!

Python 装饰器(进阶篇)的更多相关文章

  1. (转)python装饰器进阶一

    Python装饰器进阶之一 先看例子 网上有很多装饰器的文章,上来说半天也没让人看明白装饰器到底是个什么,究竟有什么用,我们直接来看几个例子. Python递归求斐波那契数列 def fibonacc ...

  2. Python装饰器进阶

    装饰器进阶 现在,我们已经明白了装饰器的原理.接下来,我们还有很多事情需要搞清楚.比如:装饰带参数的函数.多个装饰器同时装饰一个函数.带参数的装饰器和类装饰器. 装饰带参数函数 def foo(fun ...

  3. python 装饰器 一篇就能讲清楚

    装饰器一直是我们学习python难以理解并且纠结的问题,想要弄明白装饰器,必须理解一下函数式编程概念,并且对python中函数调用语法中的特性有所了解,使用装饰器非常简单,但是写装饰器却很复杂.为了讲 ...

  4. 转发:python 装饰器--这篇文章讲的通俗易懂

    转 http://www.cnblogs.com/wupeiqi/articles/4980620.html 1.必备 #### 第一波 #### def foo():     print 'foo' ...

  5. (转)python装饰器二

    Python装饰器进阶之二 保存被装饰方法的元数据 什么是方法的元数据 举个栗子 def hello(): print('Hello, World.') print(dir(hello)) 结果如下: ...

  6. 一篇关于Python装饰器的博文

    这是一篇关于python装饰器的博文 在学习python的过程中处处受阻,之前的学习中Python的装饰器学习了好几遍也没能真正的弄懂.这一次抓住视频猛啃了一波,就连python大佬讲解装饰器起来也需 ...

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

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

  8. Python函数--装饰器进阶

    开放封闭原则 1.对扩展是开放的 为什么要对扩展开放呢? 我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改.所以我们必须允许代码扩展.添加新功能. 2.对修改是封 ...

  9. 理解 Python 装饰器看这一篇就够了

    讲 Python 装饰器前,我想先举个例子,虽有点污,但跟装饰器这个话题很贴切. 每个人都有的内裤主要功能是用来遮羞,但是到了冬天它没法为我们防风御寒,咋办?我们想到的一个办法就是把内裤改造一下,让它 ...

  10. 【转】python 面向对象(进阶篇)

    [转]python 面向对象(进阶篇) 上一篇<Python 面向对象(初级篇)>文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 ...

随机推荐

  1. 第7讲:SQL Server简介

    SQL Server是微软公司提供的一款关系数据库管理系统. 操作数据库有两种方式:SQL语句和可视化的SSMS,该文章所有操作均基于SSMS. 一.SSMS(SQL Server Managemen ...

  2. 第七周psp例行报告

    本周psp 本周进度条 代码累积折线图 博文字数累积折线图 饼状图

  3. BugPhobia准备篇章:Beta阶段前后端接口文档

    0x00:序言 Two strangers fell in love, Only one knows it wasn’t by chance. To the searching tags, you m ...

  4. 《JavaScript》数组Array

    构造函数 var arr1 = new Array();// [] 空数组 var arr2 = new Array(3);//定义长度,0是空数组 var arr3 = new Array(1,2, ...

  5. Task 6.4 冲刺Two之站立会议8

    今天团队主要进行了用户使用的部分,因为软件操作相对来说比较复杂,因为要改很多东西,比方用户注册,还有更改软件连接服务器的IP.所以我们需要对用户进行详细地讲解.

  6. 项目Beta冲刺(团队)第六天

    1.昨天的困难 可以获得教务处通知栏的15条文章数据了,但是在显示的时候出了问题. 私信聊天的交互还没研究清楚 2.今天解决的进度 成员 进度 陈家权 研究私信模块 赖晓连 研究问答模块 雷晶 研究服 ...

  7. 四则运算结对项目之GUI

    本次结对编程让我学到了许多许多知识,受益匪浅!在此之前,我没想过我能做出一个双击运行的小程序. 感谢我的队友与我同心协力,感谢室友宇欣告诉我操作符为“最多多少”而不是“多少”并教我使用效能分析工具,感 ...

  8. 四则运算截图and代码

    1.运行截图 2.代码 #include<stdio.h> #include<stdlib.h> int main() { int i=300; int a=0; while( ...

  9. php 把数字转化为大写中文

    PHP 数字转大写中文 PHP入门小菜鸟一枚.下午要求写一个把数字转成大写中文的脚本,百度了一波,几十个博客和网站都是用的那四个代码,第一个运行不了,第二个有问题,不合要求,第三个第四个太长,懒得看, ...

  10. 25_IO_第25天(Properties、序列化流、打印流、CommonsIO)_讲义

    今日内容介绍 1.Properties集合 2.序列化流与反序列化流 3.打印流 4.commons-IO 01Properties集合的特点 * A: Properties集合的特点 * a: Pr ...