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 函数自由变量的大坑的更多相关文章

  1. Python之函数进阶

    本节内容 上一篇中介绍了Python中函数的定义.函数的调用.函数的参数以及变量的作用域等内容,现在来说下函数的一些高级特性: 递归函数 嵌套函数与闭包 匿名函数 高阶函数 内置函数 总结 一.递归函 ...

  2. 【转】Python之函数进阶

    [转]Python之函数进阶 本节内容 上一篇中介绍了Python中函数的定义.函数的调用.函数的参数以及变量的作用域等内容,现在来说下函数的一些高级特性: 递归函数 嵌套函数与闭包 匿名函数 高阶函 ...

  3. Python:函数解释(面向过程)

    1. 函数概述 在编程的语境下,函数 (function) 是指一个有命名的.执行某个计算的语句序列 (sequence of statements) .函数可以针对某类问题建立了通用解决步骤(算法) ...

  4. python的函数

    函数一词起源于数学,但是在编程中的函数和数学中的有很大不同.编程中的函数式组织好的,可重复使用的,用于实现单一功能或相关联功能的代码块. 我们在学习过程中已经使用过一些python内建的函数,如pri ...

  5. python strip()函数 介绍

    python strip()函数 介绍,需要的朋友可以参考一下   函数原型 声明:s为字符串,rm为要删除的字符序列 s.strip(rm)        删除s字符串中开头.结尾处,位于 rm删除 ...

  6. python split()函数

    Python split()函数 函数原型: split([char][, num])默认用空格分割,参数char为分割字符,num为分割次数,即分割成(num+1)个字符串 1.按某一个字符分割. ...

  7. Python数学函数

    1.Python数学函数 1.abs(x):取绝对值,内建函数 2.math.ceil(x):向上取整,在math模块中 3.cmp(x,y):如果 x < y ,返回-1:如果 x == y ...

  8. Python回调函数用法实例详解

    本文实例讲述了Python回调函数用法.分享给大家供大家参考.具体分析如下: 一.百度百科上对回调函数的解释: 回调函数就是一个通过函数指针调用的函数.如果你把函数的指针(地址)作为参数传递给另一个函 ...

  9. Python之函数与变量

    本节内容 函数介绍及其作用 函数的定义与调用 函数的参数说明 全局变量与局部变量 值传递和引用传递 一.函数的介绍及其作用 编程语言中的函数与数学中的函数是有区别的:数学中的函数有参数(输入),就会有 ...

随机推荐

  1. Java 嵌套类基础详解

    目录 1. 什么是嵌套类? 2. 为什么要使用嵌套类? 3. 嵌套类的类型 4. 静态嵌套类 5. 非静态嵌套类 5.1 成员内部类 5.2 局部内部类 5.3 匿名内部类 6. 嵌套接口 1. 什么 ...

  2. 再谈angularJS数据绑定机制及背后原理—angularJS常见问题总结

    这篇是对angularJS的一些疑点回顾,是对目前angularJS开发的各种常见问题的整理汇总.如果对文中的题目全部了然于胸,觉得对整个angular框架应该掌握的七七八八了.希望志同道合的通知补充 ...

  3. MySQL慢日志功能分析及优化增强

    本文由  网易云发布. MySQL慢日志(slow log)是MySQL DBA及其他开发.运维人员需经常关注的一类信息.使用慢日志可找出执行时间较长或未走索引等SQL语句,为进行系统调优提供依据.本 ...

  4. mysql之子查询作业

    #数据准备drop table if exists class;create table class(    class_no int(2) unsigned zerofill primary key ...

  5. Redis常用命令--Sets

    Set是不重复且无序的字符串元素的集合. 还可以对set集取交集,并集,差等等. 在Redis中大概有15个操作Set的命令. SADD key member [member ...]:添加一个或者多 ...

  6. 简陋的个人Vim使用命令

    最近把Visual Studio 的编辑器改成了 Vim,感觉像发现了新世界,记录记录一些提高效率的Vim命令. 插入命令 i 在当前位置前插入 I 在当前行首插入 a 在当前位置后插入 A 在当前行 ...

  7. [HAOI2007]上升序列

    Description 对于一个给定的S={a1,a2,a3,…,an},若有P={ax1,ax2,ax3,…,axm},满足(x1 < x2 < … < xm)且( ax1 < ...

  8. ●洛谷P2495 [SDOI2011]消耗战

    题链: https://www.luogu.org/problemnew/show/P2495题解: 虚树入门,树形dp 推荐博客:http://blog.csdn.net/lych_cys/arti ...

  9. [SPOJ962]Intergalactic Map 拆点+最大流

    Jedi knights, Qui-Gon Jinn and his young apprentice Obi-Wan Kenobi, are entrusted by Queen Padmé Ami ...

  10. HDU 4501

    超市里有n件他想要的商品.小明顺便对这n件商品打了分,表示商品的实际价值.小明发现身上带了v1的人民币,会员卡里面有v2的积分,而且他能免费拿k件.他想知道他最多能买多大价值的商品. 由于小明想要的商 ...