python中lambda表达式中自由变量的坑
来源:互联网 发布:大数据时代到来 编辑:程序博客网 时间:2024/05/21 00:45
Python中函数是一个对象, 和整数,字符串等对象有很多相似之处,例如可以作为其他函数的参数或返回对象, Python中的函数还可以携带自由变量, 两者无疑极大增进了Python的表达力.
但是Python函数自由变量的内部机制和列表解析或for循环结合使用时却暗藏杀机:
#---CASE 1fs = map(lambda i:(lambda j: i*j),range(6))print([f(2) for f in fs])#---CASE 2fs = [lambda j:i*j for i in range(6)]print([f(2) for f in fs])#---CASE 3fs = []for i in range(6): fs.append(lambda j:i*j) if i==3: breakprint([f(2) for f in fs])#---CASE 4fs = [(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 = 1def f(j): return i*jprint(f(2)) # ---> 2i = 2print(f(2)) # ---> 4def g(): i = 3 def f(j): return i*j return ff = g()print(f(2)) # ---> 6i = 100print(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 2fs = [lambda j:i*j for i in range(6)]print([f(2) for f in fs])i = 4print([f(2) for f in fs])#---CASE 3fs = []for i in range(6): fs.append(lambda j:i*j)print([f(2) for f in fs])i = 4print([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]
0 0
- python中lambda表达式中自由变量的坑
- Python中lambda表达式
- Python中lambda表达式
- Python中lambda表达式
- Python中lambda表达式
- python中lambda表达式的使用
- Python中lambda表达式的应用
- Python中lambda表达式学习
- Python中lambda表达式详解
- Python中lambda表达式学习
- Python中lambda表达式学习
- Python中lambda表达式学习
- Python中lambda表达式学习
- Python中lambda表达式学习
- Python中lambda表达式学习
- Python中lambda表达式学习
- Python中lambda表达式学习
- Lambda FAQ_9.Lambda表达式中能使用外部环境的变量吗?
- 上传List集合 (List<实体类>转json)
- CentOS7禁用防火墙相关命令
- Maven 项目打包
- HIVE中NULL值的处理
- Android 虚线出不来的问题解决方法
- python中lambda表达式中自由变量的坑
- 每天一个Linux命令(29):gzip
- TCP与UDP
- java 幂等性
- 猴子理论——高效管理的一种方式
- 如何逆向逐层输出树中的元素
- POJ 3070 Fibonacci
- TLS协议分析 (七) 安全性分析
- 表格整理