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

    地址: https://github.com/aamirafridi/jQuery.Marquee <script language="JavaScript" src=&qu ...

  2. 使用UML进行项目开发

    一.概述 本文主要论述的内容是如何使用UML来指导(辅助)项目设计.在此篇文章中,假设读者对UML已经有了概念上的认识,对UML中出现的名词都能很好的理解. UML的目标是以面向对象图的方式来描述任何 ...

  3. Codeforces Round #370 (Div. 2) C

    Description Memory is now interested in the de-evolution of objects, specifically triangles. He star ...

  4. ContentProvider官方教程(9)定义一个provider完整示例:实现方法,定义权限等

    Creating a Content Provider In this document Designing Data Storage Designing Content URIs Implement ...

  5. 函数式编程之block

    语法: 注意: 1,在代码块中可以使用和改变全局变量 2,而局部变量可以使用,但是不能改变. 怎么在代码块中改变局部变量呢?在局部变量前面加上关键字:__block 参考: Objective-C语法 ...

  6. HTML框架与布局

    原文:http://www.cnblogs.com/yyhh/p/4210659.html HTML块 HTML块元素 块元素在显示时,通常会以新行开始 如:<h1>.<p>. ...

  7. HTTP传送协议

    HTTP传送协议--学习笔记 HTTP数据传输格式 基本格式为: 请求或应答行 请求或应答头部 空行 数据 POST传送格式 底层数据通信: 客户端请求: POST /response.php HTT ...

  8. [数据结构与算法]队列Queue 的多种实现

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  9. [SAP ABAP开发技术总结]搜索帮助Search Help (F4)

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  10. 线程入门之实现Runnable接口和继承Thread类

    线程的2种使用方式:实现Runnable接口和继承Thread类 1.实现Runnable接口 实现Runnable接口,必须实现run方法,也是Runnable接口中的唯一一个方法 class Ru ...