百度搜了一下闭包的概念:简而言之,闭包的作用就是在外部函数执行完并返回后,闭包使得收机制不会收回函数所占用的资源,因为内部函数的执行需要依赖外函数中的变量。这是对闭包作用的非常直白的描述,不专业也不严谨,但大概意思就是这样,理解闭包需要循序渐进的过程。
我自己的理解,就是给自己看的,也希望大神指点:闭包在外函数返回的内涵数,内函数用到了外函数的参数,并没有在整个函数外部声明一个参数用来存执行这个方法时希望存下来的值,仅仅在声明外函数得到内涵数的句柄时将参数的值持久,外函数和内函数相互引用,而又不受外界打扰。像下面的第一段代码,在count1不被回收的时候,5的这个值是一直被count1所引用的,在count1不被垃圾回收机制回收之前一直有效,外界却改变不了这个值,如果在生命一个count2,那又是count2自己的领域,和count1完全没关系。

在看书中的闭包的问题的时候,发现给了这样一段代码:

def counter(start_at=0):
count = [start_at]
def incr():
print count
count[0] += 1
return count[0]
return incr
count1 = counter(5)
count1()
结果:6

结果和预想的一样。但是发现了一个问题,count = [start_at]这个地方是用一个数组来封装的,为什么要弄成这样,于是自己修改了一下,数组去掉

def counter(start_at=0):
count = start_at
def incr():
print count
count += 1
return count
return incr
count1 = counter(5)
print count1()

(关于下面问题的研究,参考     http://linluxiang.iteye.com/blog/789946   )
运行报错:UnboundLocalError: local variable 'count' referenced before assignment
原因编译器看到a=a+1,检查右边发现了一个a的变量。编译器根据自己的规则(如果一个名字出现在参数声明,赋值语句(左边),函数声明,类声明,import语句,for语句和except语句中,这就是一个局部变量。)。编译器从头到尾看一遍,在a=a+1右边找到了a,决定他就是一个本地变量。编译器顺利赋值,但是在虚拟机运行的时候,虚拟机在计算a=a+1的时候并没有找到a的声明,于是报错。为什么数组正常,因为数组中的仅仅是一个引用。python的名字查找顺序:先local,再闭包,在global。

在记录一下闭包和装饰器的使用:

方法的参数也可以是方法:
deco方法中将原方法返回去,但是这么弄发现只有第一次(deco(func))的时候才调了装饰方法。

def deco(func):
print 'before func'
func()
print 'after func'
return func
def func():
print 'hello, bad_boy'
myfunc = deco(func)
myfunc()
myfunc()
结果:

  before func
  hello, bad_boy
  after func
  hello, bad_boy
  hello, bad_boy

怎么每次都调用新方法稍后在说,先看看怎么用装饰器来完成上面的功能。

def deco(func):
print 'before func'
func()
print 'after func'
return func
@deco
def func2():
print 'hello, bad_boy, hahaha'
func2()
func2()
结果
before func
hello, bad_boy, hahaha
after func
hello, bad_boy, hahaha
hello, bad_boy, hahaha

这里在声明func2的时候,就走了一遍deco方法,以后的每次调用都是deco中return 回来的那个方法,也就是func2。

然后解决上面留下的问题:

def deco1(func):
def inner_deco():
print 'before func'
result = func()
print 'after func'
return result
return inner_deco
@deco1
def func3():
print 'hello, bad_boy, hahaha'
func3()
func3()
结果:
before func
hello, bad_boy, hahaha
after func
before func
hello, bad_boy, hahaha
after func

每次调用都是调用的新的方法,最主要的是,在声明方法func3的时候,也就仅仅是一个声明,并没有执行,这是因为在deco1方法中,没有传进方法的执行语句,执行语句func()在inner_deco内部,而deco1方法仅仅返回的是inner_deco句柄。这段代码其实就是相当于func = deco1(func3)。
给方法中加上参数:

def deco2(func):
def inner_deco(x , y):
print 'before func'
result = func(x , y)
print 'after func'
return result
return inner_deco @deco2
def func4(x , y):
print 'x is ', x
print 'y is ', y
return x + y
print func4(1, 2)
结果:
before func
x is 1
y is 2
after func
3

如果在写inner_deco的时候,并不知道外面会传什么参数,那就用*args, **kwargs,下面会用到。
装饰器上也带有参数,借用《Python核心编程》中的例子

from time import time

def logged(when):
def log(f, *args, **kargs):
print '''Called:
function: %s
args: %r
kargs: %r''' % (f, args, kargs) def pre_logged(f):
def wrapper(*args, **kargs):
log(f, *args, **kargs)
return f(*args, **kargs)
return wrapper def post_logged(f):
def wrapper(*args, **kargs):
now = time()
try:
log(f, *args, **kargs)
return f(*args, **kargs)
finally:
print "time delta: %s" % (time() - now)
return wrapper
try:
return {"pre": pre_logged, "post": post_logged}[when]
except KeyError, e:
raise ValueError(e), 'must be "pre" or "post"' @logged("post")
def hello(name):
print "Hello,", name hello("World!")

如果想要在装饰器中也添加参数,也就得在包一层函数。理解一下,首先,到这里已经明白了,其实装饰器就是另外一个方法,方法中有参数,肯定得需要接受,在第一层函数中,是一定要接受装饰器参数的。装饰器的主要作用就是用来修饰一个方法,给这个方法添加一些额外的功能。一定会有一层函数来把要修饰的方法传进去,第二层函数就是来传递方法。方法传进来了还要有一层来执行这个方法。如果不用装饰器的方法(@logged("post")删掉),就是func = logged('post')(hello)      func('World!')这两句和利用装饰器的hello("World!")是等价的。

 

Python核心编程-闭包的更多相关文章

  1. Python核心编程的四大神兽:迭代器、生成器、闭包以及装饰器

      生成器 生成器是生成一个值的特殊函数,它具有这样的特点:第一次执行该函数时,先从头按顺序执行,在碰到yield关键字时该函数会暂停执行该函数后续的代码,并且返回一个值:在下一次调用该函数执行时,程 ...

  2. python核心编程第二版笔记

    python核心编程第二版笔记由网友提供:open168 python核心编程--笔记(很详细,建议收藏) 解释器options:1.1 –d   提供调试输出1.2 –O   生成优化的字节码(生成 ...

  3. python核心编程--笔记

    python核心编程--笔记 的解释器options: 1.1 –d   提供调试输出 1.2 –O   生成优化的字节码(生成.pyo文件) 1.3 –S   不导入site模块以在启动时查找pyt ...

  4. Python核心编程第二版(中文).pdf 目录整理

    python核心编程目录 Chapter1:欢迎来到python世界!-页码:7 1.1什么是python 1.2起源  :罗萨姆1989底创建python 1.3特点 1.3.1高级 1.3.2面向 ...

  5. python核心编程--笔记(不定时跟新)(转)

    的解释器options: 1.1 –d   提供调试输出 1.2 –O   生成优化的字节码(生成.pyo文件) 1.3 –S   不导入site模块以在启动时查找python路径 1.4 –v   ...

  6. python核心编程笔记(转)

    解释器options: 1.1 –d   提供调试输出 1.2 –O   生成优化的字节码(生成.pyo文件) 1.3 –S   不导入site模块以在启动时查找python路径 1.4 –v   冗 ...

  7. Python核心编程(第二版)PDF

    Python核心编程(第二版) 目录 第1部分 Python核心第1章 欢迎来到Python世界1.1 什么是Python1.2 起源1.3 特点1.3.1 高级1.3.2 面向对象1.3.3 可升级 ...

  8. 拒绝从入门到放弃_《Python 核心编程 (第二版)》必读目录

    目录 目录 关于这本书 必看知识点 最后 关于这本书 <Python 核心编程 (第二版)>是一本 Python 编程的入门书,分为 Python 核心(其实并不核心,应该叫基础) 和 高 ...

  9. Python核心编程(第3版)PDF高清晰完整中文版|网盘链接附提取码下载|

    一.书籍简介<Python核心编程(第3版)>是经典畅销图书<Python核心编程(第二版)>的全新升级版本.<Python核心编程(第3版)>总共分为3部分.第1 ...

随机推荐

  1. Thinkphp3.2.3如何加载自定义函数库

    方法一:将自定义函数库放在Common文件夹下的Common文件夹下,命名为function.php. 方法二:项目配置文件中定义LOAD_EXT_FILE参数.这个方法在3.1的开发手册中有. 参考 ...

  2. flash压力测试

    涉及目录: vendor/mediatek/proprietary/bootable/bootloader/preloader/platform/mt6735/src/drivers/inc/dram ...

  3. Java总结反射

    [案例1]通过一个对象获得完整的包名和类名 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package Reflect;   /**  * 通过一个对象获得完整的包名和类名 ...

  4. MVC2.0==>MVC3.0

    总结出如下4个MVC3.0和2.0的重要区别. 1. @ 符号在 View 页面中的用法: C#代码以 @符号开头,例如 1 <h2>Name: @Model.Name</h2> ...

  5. Linux新手学堂 Crontab命令的语法

    crontab 命令的用途就是:提交.编辑.列出或除去 cron 作业. 语法 crontab [ -e [UserName] | -l [UserName] | -r [UserName] | -v ...

  6. qt 3 获取文件路径中的一部分

    QList<QString> qlist = path.split(QRegExp("[\\\\/]")); QString FileName = qlist.at(q ...

  7. iOS深入学习(UITableView系列4:使用xib自定义cell)

    可以通过继承UITableViewCell重新自定义cell,可以像下面一样通过代码来自定义cell,但是手写代码总是很浪费时间, ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ...

  8. 统计fastq文件中读段的数量

    mycount=`cat SRR108114_new_1.fastq | wc -l` echo 'Number of clean reads, SRR108114_new_1.fastq: '$(( ...

  9. [HDOJ5877]Weak Pair(DFS,线段树,离散化)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5877 题意:给一棵树和各点的权值a,求点对(u,v)个数,满足:1.u是v的祖先,2.a(u)*a(v ...

  10. CUBRID学习笔记 43 insert into

    cubrid的中sql查询语法insert into ------ 官方文档是英文的,看不明白可以参看ocracle的同类函数说明.很多都是一样的. INSERT INTO a_tbl1(id) VA ...