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

    题目链接:http://poj.org/problem?id=2253 题意: 给出两只青蛙的坐标A.B,和其他的n-2个坐标,任一两个坐标点间都是双向连通的.显然从A到B存在至少一条的通路,每一条通 ...

  2. IOSView翻转扭矩位移

    CoreGraphics.h CGAffineTransform rotation = CGAffineTransformMakeRotation(M_PI_2);[xxx setTransform: ...

  3. [CSAPP-II] 链接[符号解析和重定位] 静态链接 动态链接 动态链接接口

    1 平台 转http://blog.csdn.net/misskissc/article/details/43063419 1.1 硬件 Table 1. 硬件(lscpu) Architecture ...

  4. POJ 3320 Jessica's Reading Problem 尺取法

    Description Jessica's a very lovely girl wooed by lots of boys. Recently she has a problem. The fina ...

  5. 三、java中的流程控制

    流程控制:1.分类:顺序结构.选择结构.循环结构.2.顺序结构:依次执行.3.选择结构:if.if...else.if...else if...else:三目运算符(表达式?为true的执行语句:为f ...

  6. 一、java环境搭建

    结论: 1.jdk包括jre,jre包括jvm. 2.eclipse ide依赖环境变量.如果未设置,在启动eclipse工具会提示:返回码是13.

  7. mysql 修改数据库的列

    alter table tableName oldcolumn newcolumn datatype;

  8. 简单封装JDBC

    package com.sunshine.frimework.tool;import java.sql.Connection;import java.sql.DriverManager;import ...

  9. van Emda Boas

    van Emda Boas维护了一个整数集合[0,Max)(无重复),其中Max必须等于2的正整数次幂.它支持以下操作:(1)插入一个数字;(2)删除一个数字:(3)询问某一个数字在不在这个集合中:( ...

  10. [Unity2D]Tags和Layers

    Tags和Layers分别表示是Unity引擎里面的标签和层,他们都是用来对GameObject进行标识的属性,Tags常用于单个GameObject,Layers常用于一组的GameObject.添 ...