Python 3 函数自由变量的大坑
Python中函数是一个对象, 和整数,字符串等对象有很多相似之处,例如可以作为其他函数的参数或返回对象, Python中的函数还可以携带自由变量, 两者无疑极大增进了Python的表达力.
但是Python函数自由变量的内部机制和列表解析或for循环结合使用时却暗藏杀机:
#---CASE 1
fs = map(lambda i:(lambda j: i*j),range(6))
print([f(2) for f in fs]) #---CASE 2
fs = [lambda j:i*j for i in range(6)]
print([f(2) for f in fs]) #---CASE 3
fs = []
for i in range(6):
fs.append(lambda j:i*j)
if i==3:
break
print([f(2) for f in fs]) #---CASE 4
fs = [(lambda i:lambda j:i*j)(i) for i in range(6)]
print([f(2) for f in fs])
结果:
[0, 2, 4, 6, 8, 10]
[10, 10, 10, 10, 10, 10]
[6, 6, 6, 6]
[0, 2, 4, 6, 8, 10]
可以通过下面这个简单的测试来分析Python函数在执行时是如何确定自由变量的值的:
i = 1
def f(j):
return i*j
print(f(2)) # ---> 2 i = 2
print(f(2)) # ---> 4 def g():
i = 3
def f(j):
return i*j
return f
f = g()
print(f(2)) # ---> 6 i = 100
print(f(2)) # ---> 6
可见,当 函数f在*定义时*, Python不会记录自由变量'i'对应什么对象, 只会告诉f, 你有一个自由变量, 它的名字叫 'i'.
接着, 当函数f在*执行时*, Python告诉f:
(1) 空间上: 你需要在你被*定义时*的外层namespace里面去查找i对应的对象, 假设这个namespace为X.
(2) 时间上: 是在你*当前运行时*, X 里面的 i 对应的对象.
上面那个简单测试中的 i = 2 之后, f(2)随之也返回4也能反映了这一点.
CASE 2和3 也是如此, fs里面每个函数对应的自由变量i在*定义时*都是循环变量i, 因此*执行时*都是对应循环结束或跳出时i所指对象.
而 CASE 1和4为什么能如愿发生变化呢? 这是因为函数对应的自由变量i不再是循环变量i, 而是外层lambda函数*执行时*,循环变量i所指对象在其栈上的拷贝, 由于每次调用外层lambda时i所指对象都不相同, 因此每个函数的自由变量也会指向不同的对象.
最后, 列表解析里面的作用域是一个全新的作用域, 而普通的for循环则有所不同. 例如:
#---CASE 2
fs = [lambda j:i*j for i in range(6)]
print([f(2) for f in fs])
i = 4
print([f(2) for f in fs]) #---CASE 3
fs = []
for i in range(6):
fs.append(lambda j:i*j)
print([f(2) for f in fs])
i = 4
print([f(2) for f in fs])
结果是:
[10, 10, 10, 10, 10, 10]
[10, 10, 10, 10, 10, 10]
[10, 10, 10, 10, 10, 10]
[8, 8, 8, 8, 8, 8]
Python 3 函数自由变量的大坑的更多相关文章
- Python之函数进阶
本节内容 上一篇中介绍了Python中函数的定义.函数的调用.函数的参数以及变量的作用域等内容,现在来说下函数的一些高级特性: 递归函数 嵌套函数与闭包 匿名函数 高阶函数 内置函数 总结 一.递归函 ...
- 【转】Python之函数进阶
[转]Python之函数进阶 本节内容 上一篇中介绍了Python中函数的定义.函数的调用.函数的参数以及变量的作用域等内容,现在来说下函数的一些高级特性: 递归函数 嵌套函数与闭包 匿名函数 高阶函 ...
- Python:函数解释(面向过程)
1. 函数概述 在编程的语境下,函数 (function) 是指一个有命名的.执行某个计算的语句序列 (sequence of statements) .函数可以针对某类问题建立了通用解决步骤(算法) ...
- python的函数
函数一词起源于数学,但是在编程中的函数和数学中的有很大不同.编程中的函数式组织好的,可重复使用的,用于实现单一功能或相关联功能的代码块. 我们在学习过程中已经使用过一些python内建的函数,如pri ...
- python strip()函数 介绍
python strip()函数 介绍,需要的朋友可以参考一下 函数原型 声明:s为字符串,rm为要删除的字符序列 s.strip(rm) 删除s字符串中开头.结尾处,位于 rm删除 ...
- python split()函数
Python split()函数 函数原型: split([char][, num])默认用空格分割,参数char为分割字符,num为分割次数,即分割成(num+1)个字符串 1.按某一个字符分割. ...
- Python数学函数
1.Python数学函数 1.abs(x):取绝对值,内建函数 2.math.ceil(x):向上取整,在math模块中 3.cmp(x,y):如果 x < y ,返回-1:如果 x == y ...
- Python回调函数用法实例详解
本文实例讲述了Python回调函数用法.分享给大家供大家参考.具体分析如下: 一.百度百科上对回调函数的解释: 回调函数就是一个通过函数指针调用的函数.如果你把函数的指针(地址)作为参数传递给另一个函 ...
- Python之函数与变量
本节内容 函数介绍及其作用 函数的定义与调用 函数的参数说明 全局变量与局部变量 值传递和引用传递 一.函数的介绍及其作用 编程语言中的函数与数学中的函数是有区别的:数学中的函数有参数(输入),就会有 ...
随机推荐
- 关于Java中的Null
什么是Java中的Null? null在Java中是一个非常重要的概念,它最初是为了表示缺少某些东西,例如缺少用户.资源或任何东西而发明出来的.但是这也为Java程序员带来了很多麻烦,比如最常见的空指 ...
- 初学servlet之@WebServlet传参
package app01a;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.ServletCon ...
- [NOIp 2014]飞扬的小鸟
Description Flappy Bird 是一款风靡一时的休闲手机游戏.玩家需要不断控制点击手机屏幕的频率来调节小鸟的飞行高度,让小鸟顺利通过画面右方的管道缝隙.如果小鸟一不小心撞到了水管或者掉 ...
- codeforces round #419 E. Karen and Supermarket
On the way home, Karen decided to stop by the supermarket to buy some groceries. She needs to buy a ...
- 【luogu3174】【HAOI2009】毛毛虫
Description 对于一棵树,我们可以将某条链和与该链相连的边抽出来,看上去就象成一个毛毛虫,点数越多,毛毛虫就越大. Input 在文本文件 worm.in 中第一行两个整数 N , M ,分 ...
- [51nod1238]最小公倍数之和V3
来自FallDream的博客,未经允许,请勿转载,谢谢. ----------------------------------------------------------------------- ...
- 5分钟快速打造WebRTC视频聊天
百度一下WebRTC,我想也是一堆.本以为用这位朋友( 搭建WebRtc环境 )的SkyRTC-demo 就可以一马平川的实现聊天,结果折腾了半天,文本信息都发不出去,更别说视频了.于是自己动手. 想 ...
- ESLint规范
配置如下:{ // 环境定义了预定义的全局变量. "env": { //环境定义了预定义的全局变量.更多在官网查看 "browser":true, " ...
- win10下python环境变量设置
我用的是python_2.7.3.msi,从官网下载之后,一路按照默认进行安装. 安装之后配置环境变量的步骤如下: 1,点“我的电脑”,右键选“属性” 2,选择“高级系统设置”--->选“环境变 ...
- 遗传算法:N皇后
N皇后问题描述 N皇后问题是一个经典的问题,在一个N*N的棋盘上放置N个皇后,每行一个并使其不能互相攻击(同一行.同一列.同一斜线上的皇后都会自动攻击). 遗传算法 遗传算法是局部束搜索的变形: 与自 ...