理解Python的装饰器
看Flask文档时候看到关于cache的装饰器,有这么一段代码:
def cached(timeout=5 * 60, key=’view/%s’):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
cache_key = key % request.path
rv = cache.get(cache_key)
if rv is not None:
return rv
rv = f(*args, **kwargs)
cache.set(cache_key, rv, timeout=timeout)
return rv
return decorated_function
return decorator
之前也略懂装饰器,但是仔细一看发现了区别。
一般的装饰器代码是这样的:
def login_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if g.user is None:
return redirect(url_for(’login’, next=request.url))
return f(*args, **kwargs)
return decorated_function
看出区别了吗?
第一个里面有两层def,第二个只有一层!
我的好奇心一下就上来了,非要把这个东西搞明白不可。
研究了一会总算研究明白了,下面就开始讲解吧。
首先理解一般的装饰器到底是怎么工作的:
def login_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if g.user is None:
return redirect(url_for(’login’, next=request.url))
return f(*args, **kwargs)
return decorated_function @login_required
def test():
print "haha"
我们用login_required装饰了test函数,那么实际上执行的语句可以理解成这样:
test = login_required(test)
也就是说,现在test变成了login_required(test)的执行结果,也就是变成了decorated_function函数。
所以我们每次执行test的时候,其实执行的就是decorated_function,而原来的test函数就变成了decorated_function中的f函数。实现了装饰功能。
下面我们看看两层嵌套的装饰器到底是怎么工作的:
def cached(timeout=5 * 60, key=’view/%s’):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
cache_key = key % request.path
rv = cache.get(cache_key)
if rv is not None:
return rv
rv = f(*args, **kwargs)
cache.set(cache_key, rv, timeout=timeout)
return rv
return decorated_function
return decorator @cached(100)
def test():
pass
好像没什么区别?
再仔细看看!
@cached(100)
这里多了个参数!
是的,秘密就在这个参数。
加了参数之后,装饰器的装饰过程变成了两步:
cached_temp = cached(100)
test = cached_temp(test)
Python内部肯定没有cached_temp这个变量,这是我加的。不过实际的执行过程就是这么个顺序,这下就一目了然了吧!
首先运行cached(100),这时候返回的是第一层def,也就是真正的装饰器。
然后运行cached_temp(test),这时候返回了第二层def,这步就和一般的装饰器一样了。
我们总结一下,嵌套两层def的目的就是实现“带参装饰器”,相当于可以通过参数来定制一个装饰器,然后再应用到函数上。
明白了吗?
理解Python的装饰器的更多相关文章
- 正确理解python的装饰器
一直在用别人写的装饰器,从来没有对其原理进行深入的探究.今天趁有点闲着的时间,把装饰器的原理好好看了一遍,做一下整理. 一.装饰器的基本原理 装饰器就是一个可以接受调用也可以返回调用的调用.装饰器本身 ...
- 理解Python中的装饰器//这篇文章将python的装饰器来龙去脉说的很清楚,故转过来存档
转自:http://www.cnblogs.com/rollenholt/archive/2012/05/02/2479833.html 这篇文章将python的装饰器来龙去脉说的很清楚,故转过来存档 ...
- 关于python的装饰器(初解)
在python中,装饰器(decorator)是一个主要的函数,在工作中,有了装饰器简直如虎添翼,许多公司面试题也会考装饰器,而装饰器的意思又很难让人理解. python中,装饰器是一个帮函数动态增加 ...
- 【转】详解Python的装饰器
原文链接:http://python.jobbole.com/86717/ Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现 ...
- python之装饰器详解
这几天翻看python语法,看到装饰器这里着实卡了一阵,最初认为也就是个函数指针的用法,但仔细研究后发现,不止这么简单. 首先很多资料将装饰器定义为AOP的范畴,也就是Aspect Oriented ...
- python基础—装饰器
python基础-装饰器 定义:一个函数,可以接受一个函数作为参数,对该函数进行一些包装,不改变函数的本身. def foo(): return 123 a=foo(); b=foo; print(a ...
- 详解Python的装饰器
Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现了say_hello()和say_goodbye()两个函数. def sa ...
- 【转】Python之装饰器
[转]Python之装饰器 本节内容 必要知识回顾 情景模拟 装饰器的概念及实现原理 回马枪(带参数的装饰器) 一. 必要知识回顾 在开始说装饰器之前,需要大家熟悉之前说过的相关知识点: 函数即“变量 ...
- 如何用python的装饰器定义一个像C++一样的强类型函数
Python作为一个动态的脚本语言,其函数在定义时是不需要指出参数的类型,也不需要指出函数是否有返回值.本文将介绍如何使用python的装饰器来定义一个像C++那样的强类型函数.接下去,先介绍 ...
随机推荐
- Join Resig's “Simple JavaScript Inheritance ”
======================Enein翻译========================= John Resig 写了一篇关于 JavaScript 里类似其它语 ...
- 「CF375D Tree and Queries」
题目 \(dsu\ on\ tree\)的板子题了 \(dsu\ on\ tree\)本质上一种优秀通过轻重链剖分优化到\(O(nlogn)\)的暴力 一般用来解决没有修改的允许离线的子树查询问题 首 ...
- jquery ajax 标准写法
$.ajax({ url:"http://www.microsoft.com", //请求的url地址 dataType:"json", //返回格式为json ...
- Codeforces Round #527 (Div. 3) F. Tree with Maximum Cost 【DFS换根 || 树形dp】
传送门:http://codeforces.com/contest/1092/problem/F F. Tree with Maximum Cost time limit per test 2 sec ...
- ethereumjs/ethereumjs-account-1-简介和API
https://github.com/ethereumjs/ethereumjs-account Encoding, decoding and validation of Ethereum's Acc ...
- heatmap for arcgisjsapi
在arcgis for js api 环境下使用heatmap插件. 由于最新的heatmap没有提供 for arcgisjsapi 插件,懒得研究新版本代码,所以这里用的还是老版本的heatma ...
- mysql使用Navicat 导出和导入数据库
系统环境: Win7 x64软件准备:Navicat Premium_11.2.7简体中文版下载网址:http://www.cr173.com/soft/419023.html 现在我就向大家介绍 m ...
- java连接数据库增删改查公共方法
package dao; import java.io.IOException; import java.sql.CallableStatement; import java.sql.Connecti ...
- java两种反射的区别 - Class.forName()和ClassLoader.loadClass()
在理解这两种反射机制之前,需要弄清楚java类的加载机制. 装载:通过类的全限定名获取二进制字节流(二进制的class文件),将二进制字节流转换成方法区中的运行时数据结构,在内存中生成Java.lan ...
- LeetCode28.实现strStr() JavaScript
实现 strStr() 函数. 给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始).如果不存在,则返 ...