Python的闭包(Closure)与惰性计算(Lazy Evaluation)
闭包
在一些语言中,在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。运行时,一旦外部的 函数被执行,一个闭包就形成了,闭包中包含了内部函数的代码,以及所需外部函数中的变量的引用。其中所引用的变量称作上值(upvalue)。 https://zh.wikipedia.org/wiki/%E9%97%AD%E5%8C%85_(%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6)
事实上,你可能在JavaScript那里看到过闭包,闭包在JavaScript是非常重要的常见高级特性。 我们可以来复习一下: http://blog.csdn.net/solo95/article/details/70706623
惰性计算
讲Python惰性序列时,讲到过惰性计算,在来复习一下: http://blog.csdn.net/solo95/article/details/78834041
Python中的闭包与惰性计算
闭包的基础是,语言层面要允许函数嵌套,即一个函数体里可以再包含了另一个一个函数,并且允许将函数作为返回值返回出去(这点也说明支持闭包的语言中,函数是对象的一种)。Python具备这些性质,因此也是支持闭包的语言。 闭包在Python中的使用和JavaScript不同,闭包在Python中的出现强调延迟得到结果,这点与惰性计算的特点相契合。 示例:
>>> def lazy_sum(*args): #可变参数标准写法 前面的博客提到过
... def sum():
... res = 0
... for i in args:
... res = res + i
... return res
... return sum
...
>>> lazy_sum(1, 2, 3, 4, 5) #返回值是函数
<function lazy_sum.<locals>.sum at 0x04106198>
>>> func = lazy_sum(1, 2, 3, 4, 5)
>>> func() #调用函数func时 lazy_sum()才真正执行
15
>>>
#闭包结构:
#内部函数sum引用了外部函数lazy_sum的参数和局部变量
#lazy_sum以函数sum作为返回值
#返回时,相关参数和变量都存储在sum中
需要注意的地方
- 每次调用lazy_sum, 返回的是一个不同的sum对象
- 多次调用lazy_sum,上次调用的结果不会影响下一次
- 返回函数不要引用值会发生改变的变量
#!usr/bin/env python3
# _*_coding: utf-8 _*_
def count1():
fs = []
for i in range(1, 4): #i是闭包结构中的变量,被count1中的fs所引用
def f():
return i * i
fs.append(f)
return fs
f1, f2, f3 = count1()
print(f1())
print(f2())
print(f3())
#结果
9
9
9
#由于惰性计算的原因 for循环执行完毕i等于3的时候 f才执行 务必注意闭包函数的执行时机
#解决方法 将for循环和square函数分隔开 并将循环变量做为参数传入
def count2():
def f(j):
def g():
return j * j
return g
fs = []
for i in range(1, 4):
fs.append(f(i)) #f(i)被立即执行 所以当前值被传入了f()
return fs
f4, f5, f6 = count2()
print(f4())
print(f5())
print(f6())
#结果
1
4
9
以上例子来自廖雪峰的Python教程,原帖是介绍函数作为返回值的: https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431835236741e42daf5af6514f1a8917b8aaadff31bf000#0
- 实现三遍决策树,你就会想出更快的算法!
- 将一段复杂文本变成字符串的赋值语句
- Linux下squid代理缓存服务环境部署
- linux下清除Squid缓存的方法记录
- memcached缓存知识简单梳理
- Idea 常用快捷键
- silverlight中如何方便在多个"场景"即Xaml文件之间随意切换?
- 电子签名实现的思路、困难及解决方案
- JavaScript排序算法详解
- 事件处理需小心
- Mysql读写分离方案-MySQL Proxy环境部署记录
- Mysql读写分离方案-Amoeba环境部署记录
- linux系统终端命令提示符设置(PS1)记录
- 从MapX到MapXtreme2004[10]-根据zoom值修改显示范围
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 起个简单枯燥的标题:找出连续差相同的数字
- 10分钟带你搞懂代理模式、静态代理、JDK+CGLIB动态代理
- 握草!某程序员竟然在深夜偷偷在代码里下毒!
- 自然资源部贡献的Landuse数据(2000、2010、2020)
- LoRa节点开发——SDK整体设计思路
- 01 . Nginx简介及部署
- 02 . Nginx平滑升级和虚拟主机
- LoRa节点开发——LoRaWAN节点入网代码详解
- 03 . Nginx日志配置及日志切割
- 04 . Nginx的Rewrite重写
- 05 . Nginx的反向代理与负载均衡
- 06 . Nginx静态资源缓存
- 07 . Nginx常用模块及案例
- 08 . Nginx状态码
- 09 . Nginx配置LNMP和LNMT架构