首先,来看一个一般意义的求和:

>>> def cal_sum(*args):
... sum = 0
... for i in args:
... sum = sum + i
... return sum
...
>>> cal_sum(1,2,3,4)
10

如果我们这么定义呢:

>>> def lazy_sum(*args):
... def sum():
... sum = 0
... for i in args:
... sum = sum + i
... return sum
... return sum
...
>>> l = lazy_sum(1,2,3,4)
>>> l
<function lazy_sum.<locals>.sum at 0x00E4A198>

我们发现,这种定义的函数,返回的并不是一个具体的求和,而是一个函数!来看看怎么调用这个函数:

>>> l()
10

在这个例子中,lazy_sum中又定义了一个函数sum(),这个内部函数可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这就是‘闭包’。

再来试验一下:

>>> l1=lazy_sum(1,2,3,4)
>>> l2=lazy_sum(1,2,3,4)
>>> l1==l2
False

我们发现,l1和l2互不影响!这说明lazy_sum每次调用都返回一个新函数,即使传入的参数相同。

其实,返回的函数在其定义的内部引用了局部变量args,当一个函数返回了一个函数后,其内部的局部变量还能被新函数引用。另外,返回的函数并没有立即被执行,而是直到调用了l()后才执行。通过下面的例子再来加深一下印象

例子1:

>>> def count():
... f = []
... for i in range(1,4):
... def fp():
... return i * i
... f.append(fp)
... return f
...
>>> f1,f2,f3 = count()
>>> f1()
9
>>> f2()
9
>>> f3()
9

全部都是9,并不是1,4,9.原因在于返回的函数引用了变量i,但它并没有立即执行。等三个函数都返回时,他们所引用的变量i已经变成了3,所以最终结果都是9。由此,我们要注意:以后为了避免出现乱七八糟的数据错误,返回函数不要引用任何的循环变量,或者后续会发生变化的变量。

这时你要说了,如果一定要引用循环变量,怎么办呢?方法是再创建一个函数,用该函数的参数绑定循环变量的当前值,那么无论该循环后续如何更改,已经绑定的函数参数的值都不变了:

>>> def count():
... def f(j):
... def g():
... return j*j
... return g
... fs = []
... for i in range(1,4):
... fs.append(f(i)) #f(i)立即被执行,变量i的当前值被传入f()
... return fs
...
>>> f1,f2,f3 = count()
>>> f1()
1
>>> f2()
4
>>> f3()
9

最新文章

  1. 让shell脚本在后台飞
  2. EFW框架问题收集与答疑
  3. php正规则表达式的语法
  4. ZooKeeper学习第三期---Zookeeper命令操作
  5. 闭包 (循环事件获取不到i) 和 各种解决循环获取不到i的解决方法
  6. Oracle安全漏洞2016.10报告
  7. my sql 实现批量操作及注意问题
  8. Redis Cluster集群搭建与配置
  9. Linux 杀死挂起的进程
  10. Windows Azure 安全最佳实践 - 第 3 部分:确定安全框架
  11. 使用Java操作文本文件的方法详解
  12. MT【248】$f(x)=\dfrac{1}{x-1}+\dfrac{1}{x-b}$的性质
  13. phpstorm----------phpstorm2017基本使用
  14. win32进程概念之句柄表,以及内核对象.
  15. Nginx 配置文件解析
  16. SSM到Spring Boot从零开发校园商铺平台
  17. 20145232 韩文浩 《Java程序设计》第10周学习总结
  18. C#网络编程技术SuperSocket实战项目演练
  19. zedgraph多个graphpane的处理
  20. nginx反向代理下载文件失败处理

热门文章

  1. 56岁潘石屹生日当天宣布要学编程语言Python,网友:地产商来抢码农饭碗了!
  2. Flask容器化部署原理与实现
  3. 华为ARM64服务器上手体验--不吹不黑,用实际应用来看看TaiShan鲲鹏的表现
  4. shell 循环读取文件及字符串转为数组
  5. bundle 的生成和使用
  6. Xcode10.0: NO BUNDLE URL PRESENT
  7. 大数据之Linux进阶指令
  8. IO 单个文件的多线程拷贝
  9. Orleans的深入
  10. [状态模式]实现stopwatch