下面是我对 装饰器 这一小节的总结, 以及自己的理解。

注:【本文中的代码参考上述教程】

很多时候我会把Python的很多语法与C++相融合,在C++中,函数的名称即为函数的地址,我们可以通过定义成为"函数指针"的变量,并且将函数名称赋值给该变量,那么我们在调用函数的时候,就可以直接使用该变量调用函数。

例如下面的C++的代码就是一个简单的函数指针的定义以及调用的过程。

  1. #include <iostream>
  2. using namespace std;
  3. int f(int x, int y)
  4. {
  5. return x+y;
  6. }
  7. int main(void)
  8. {
  9. int (*fptr)(int,int) ; //定义函数指针便令fptr。
  10. fptr = f;
  11. cout << (*fptr)(2,3) << endl;
  12. return 0;
  13. }
#include <iostream>
using namespace std; int f(int x, int y)
{
return x+y;
} int main(void)
{
int (*fptr)(int,int) ; //定义函数指针便令fptr。
fptr = f;
cout << (*fptr)(2,3) << endl;
return 0;
}

在Python中,函数也是对象,并且函数对象可以被赋值给变量。通过该变量也可以调用函数,像上面一样。但是Python是动态语言,不用那么复杂的定义变量的类型,就像上面的fptr。直接可以赋值即可。

例如下面的简单的Python代码:

  1. def date():
  2. print "2014-11-5"
  3. f = date // f便是函数指针
  4. date()
  5. f()
def date():
print "2014-11-5"
f = date // f便是函数指针
date()
f()

函数对象都有一个属性__name__,可以得到函数的名字: 例如: f.__name__ 为date。

下面开始进入正题,decorator是什么,decorator是一个返回函数的高阶函数。例如,我们的一个简单的log函数,该函数在每次函数调用时做日志的工作。但是我们又不希望去修改每一个需要计入日志的函数的实现代码,那么decorator就派上用场了。

  1. def log(func):
  2. def wrapper(*args, **kw):
  3. print "[log] : call %s(): " %func.__name__
  4. return func(*args, **kw)
  5. return wrapper
def log(func):
def wrapper(*args, **kw):
print "[log] : call %s(): " %func.__name__
return func(*args, **kw)
return wrapper

首先,上面的函数log的参数是一个函数对象,返回值也是一个函数。

那么怎么将log函数用起来呢?很简单,在 要传入log作为参数 的函数定义的前面前面使用 @log 关键句即可。即像下面这样:

  1. @log
  2. def date():
  3. print "2014-11-5"
@log
def date():
print "2014-11-5"

这样每次调用date(),就相当于在调用log(date).  不添加 @log语句在date前,输出的结果是:

2014-11-5

加上@log语句之后的输出结果为:

[log] : call date()

2014-11-5

也就是说在添加了log之后,函数的调用等价与log(date),log函数的参数是date,返回的是wrapper。可以看到,wrapper可以接受任何参数的函数,在wrapper函数内部,首先打印log行,再调用原始的函数。

这里的简答的理解就是,函数在调用之前,如果被做了包裹,也就是在函数定义之前使用了@关键字,那么我们调用的就是相应的包裹函数。例如上面的调用date时调用的其实是log(date)。

这里可能存在的问题时,前面讲到说函数是个对象,有一个__name__属性,但是你会发现上述的date函数在经过装饰之后的__name__属性是wrapper。这样对于这个__name__有依赖的代码就会出现问题,因此我们需要的是 wrapper.__name__ = date.__name__的语句的功能,这个在python中可以简单使用下面的代码来实现。也就是装饰函数的完整版本:

  1. import functools
  2. def log(func):
  3. @functools.wraps(func)
  4. def wrapper(*args, **kw):
  5. print "call %s : " %func.__name__
  6. return func(*args, **kw)
  7. return wrapper
import functools
def log(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print "call %s : " %func.__name__
return func(*args, **kw)
return wrapper

使用模块functools中得wraps函数就可以实现。

上述讲述了装饰者模式,下面给出一个比较完整的例子。

  1. #!/usr/bin/env python
  2. import sys
  3. #decorator
  4. import functools
  5. def log(func):
  6. @functools.wraps(func)
  7. def wrapper(*args, **kw):
  8. print "[log] : call %s(): " %func.__name__
  9. f = func(*args, **kw)
  10. return f
  11. return wrapper
  12. date()
  13. print date.__name__
#!/usr/bin/env python
import sys #decorator import functools
def log(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print "[log] : call %s(): " %func.__name__
f = func(*args, **kw)
return f
return wrapper date()
print date.__name__

代码结果输出为:

[log] : call date():

2014-11-5

date

如果log函数本身是有参数的话,那么decorator模式就需要再加上一层传入log函数本身的参数,代码为:

  1. import functools
  2. def log(text):
  3. def decorator(func):
  4. @functools.wraps(func)
  5. def wrapper(*args, **kw):
  6. print "%s %s" %(text,func.__name__)
  7. return func(*args, **kw)
  8. return wrapper
  9. return decorator
  10. print "Test full implementation of decorator"
  11. @log("paramete of log")
  12. def date():
  13. print "2014-11-5"
  14. date()
import functools
def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print "%s %s" %(text,func.__name__)
return func(*args, **kw)
return wrapper
return decorator print "Test full implementation of decorator"
@log("paramete of log")
def date():
print "2014-11-5"
date()

此时调用log函数就等价于调用 log("parameter of log")(date) ,函数log的返回值是decorator函数,再将date作为参数传递给decorator函数,实现调用。

下面用一个最完整的例子作为结束:

  1. #!/usr/bin/env python
  2. import functools
  3. def log(text):
  4. def decorator(func):
  5. @functools.wraps(func)
  6. def wrapper(*args, **kw):
  7. print "%s %s()" %(text, func.__name__)
  8. return func(*args, **kw)
  9. return wrapper
  10. return decorator
  11. def log2(func):
  12. def decorator(*args, **kw):
  13. return func(*args, **kw)
  14. return decorator
  15. @log("decorator need parameter version1")
  16. @log("decorator need parameter version2")
  17. def date2(x,y):
  18. print "2014-11-5"
  19. print "x, y ", x, y
  20. return x
  21. date2 = log('execute1')(date2)
  22. date2 = log('execute2')(date2)
  23. date2 = log('execute3')(date2)
  24. date2(2, 3)
#!/usr/bin/env python

import functools
def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print "%s %s()" %(text, func.__name__)
return func(*args, **kw)
return wrapper
return decorator def log2(func):
def decorator(*args, **kw):
return func(*args, **kw)
return decorator @log("decorator need parameter version1")
@log("decorator need parameter version2")
def date2(x,y):
print "2014-11-5"
print "x, y ", x, y
return x date2 = log('execute1')(date2)
date2 = log('execute2')(date2)
date2 = log('execute3')(date2)
date2(2, 3)

输出结果为:

execute3 date2()

execute2 date2()

execute1 date2()

decorator need parameter version1 date2()

decorator need parameter version2 date2()

2014-11-5

x, y  2 3

重点总结:

1、装饰器装饰完函数后  再调用函数其实是操作的里面的函数

2、@functools.wraps(func)   这个装饰器解决了这个问题

项目解析1、登录验证用户是否存在 储备知识 Python 之 decorator装饰器的更多相关文章

  1. 练习:python 操作Mysql 实现登录验证 用户权限管理

    python 操作Mysql 实现登录验证 用户权限管理

  2. Session (简介、、相关方法、流程解析、登录验证)

    Session简介 Session的由来 Cookie虽然在一定程度上解决了"保持状态"的需求,但是由于Cookie本身最大支持4096字节,以及Cookie本身保存在客户端,可能 ...

  3. 【Python】解析Python中的装饰器

    python中的函数也是对象,函数可以被当作变量传递. 装饰器在python中功能非常强大,装饰器允许对原有函数行为进行扩展,而不用硬编码的方式,它提供了一种面向切面的访问方式. 装饰器 一个普通的装 ...

  4. shiro登录验证简单理解

    这两天接手了下师兄的项目,要给系统加个日志管理模块,其中需要记录登录功能的日志,那么首先要知道系统的登录是在哪里实现验证的. 该系统把所有登录验证还有权限控制的工作都交给了shiro. 这篇文章就先简 ...

  5. Django(十六)基于模板的登录案例:登录装饰器、csrf攻击方式及防护、ajax的Post 的csrf开启写法、生成验证码、加验证码登录、反向解析+传参

    一.csrf攻击 1.1 csrf攻击(跨站请求伪造) [csrf攻击即]:通过第3方网站,伪造请求(前提条件是你已经登录正常网站,并保存了session或cookie登录信息且没有退出),第三方网站 ...

  6. Flask10 登录模块、表单框架、表单渲染、表单验证、bookie、请求之前钩子、g对象、编写装饰器

    from flask import Flask from flask import request from flask import render_template from flask_wtf i ...

  7. Flask 通过扩展来实现登录验证

    1. flask扩展 说明: flask的扩展类似于python中的装饰器,和Django中的process_request的方法也类似 测试代码 from flask import Flask,se ...

  8. springboot项目中使用shiro实现用户登录以及权限的验证

    欢迎大家加入我的社区:http://t.csdn.cn/Q52km 社区中不定时发红包 更加高级的验证用户权限:用户表.角色表.权限表.多表联合:https://blog.csdn.net/weixi ...

  9. 转:C4项目中验证用户登录一个特性就搞定

    转:C4项目中验证用户登录一个特性就搞定   在开发过程中,需要用户登陆才能访问指定的页面这种功能,微软已经提供了这个特性.     // 摘要:    //     表示一个特性,该特性用于限制调用 ...

随机推荐

  1. 全文检索在 MySQL

    中就是一个 FULLTEXT 类型索引.FULLTEXT 索引用于 MyISAM 表,可以在 CREATE TABLE 时或之后使用 ALTER TABLE 或 CREATE INDEX 在 CHAR ...

  2. 25. instr用法

    很多时候,我们要进行字符串匹配,在SQL语句中,我们通常使用like来达到我们搜索的目标.但经过实际测试发现,like的效率与instr函数差别相当大.下面是一些测试结果: select instr( ...

  3. 线程安全计算 AtomicLong

    一般如果我们自己写一个计数器方法,需要考虑线程安全问题,尤其高并发访问的时候. AtomicLong 已处理并发问题,直接使用.java.util.concurrent.atomic包提供多种线程安全 ...

  4. vue基础——组件(组件嵌套)

    介绍 vue中页面是由组件组成的,即以.vue结尾的文件. .vue文件由三部分组成,分别是template.script.style. 分别写html.js.css代码. 组件之间可以互相嵌套.所以 ...

  5. cmd 查看本地端口被占用程序

    netstat -ano 列出当前活动的网络连接 参数:-a所有侦听端口  -n以数字格式显示地址和端口号 -o显示进程号 tasklist|find "8888" 找出占用888 ...

  6. java是如何编码解码的

    在上篇博客中LZ阐述了java各个渠道转码的过程,阐述了java在运行过程中那些步骤在进行转码,在这些转码过程中如果一处出现问题就很有可能会产生乱码!下面LZ就讲述java在转码过程中是如何来进行编码 ...

  7. mongodb基础学习14-mapReduce操作

    mapReduce随着大数据的兴起而流行,相当于传统数据库的group操作,强项在于分布式计算. map:将一组记录的相关信息映射到一个数组 reduce:对map得到的数组数据进行处理得到一个结果 ...

  8. Mysql通过SQL脚本复制表

    create table if not exists t_dest like t_src 其中,t_src是要复制的原始表,t_dest是要创建的新表.

  9. centos7 莫名重起的问题

    ausearch -i -m system_boot,system_shutdown | tail -4----type=SYSTEM_BOOT msg=audit(2018年05月10日 07:45 ...

  10. Egit的merge合并冲突具体解决方法

    稍微总结下弄了半个下午的egit的merge合并冲突解决方法,网上看的都是一个模板出来的,看的糊里糊涂,花了很多时间去实验整个合并流程.. 前提工作 创建一个普通JAVA工程Test,创建一个类Tes ...