python3 的闭包问题
def count():fs = []
for i in range(1, 4):
def f():
return i * i
fs.append(f)
return fs
问题出现在使用这个函数的过程中:
有以下三种方式进行引用:
方式1,发生报错
>>> f1 = count()
>>> f1()
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
f1()
TypeError: 'list' object is not callable
方式2,发生报错:
>>> f1, f2 = count()
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
f1, f2 = count()
ValueError: too many values to unpack (expected 2)
方式3,正常:
>>> f3, f4, f5 = count()
>>> f3()
9
如上,问题是:
1.为什么方式1在引用的时候会报错?
2.方式2为什么在创建的时候会报错,我是没看懂报错信息
3.方式3怎么就能正常运行了?
本帖最后由 丨游戏灬需要 于 2018-11-19 23:13 编辑
1 ,f1 = count() ,但def count 的返回值是fs (是列表) ,所以报错说'列表对象
不能用"()"来"引爆"' #由于函数要加了"()"才能触发效果 ,所以我暂且称"()"为
"引爆"
2 ,报错说'太多的值以至于不能解压/分配' ,这和 a ,b = ,是一种情况,
也就是说 在count()函数里 ,fs的列表里的值的个数超过了2
3 ,模拟 conut()的结果 ,在count里 ,
#里面未'引爆'的f用lambda来模拟
fs应该 =
更正一下 ,
fs储存的原来是叫做f这个函数的引用 ,所以当for循环完后 f函数的效果是:'lambda : 3*3'
实质上 ,因为函数中叫做 fs的列表 添加的是没有'引爆'的 f 函数 ,所以是 f 这个函数的引用 ,如果是'引爆'了的 ,
就变成了添加 独一的 f函数(不会因为 def f():… 而改变内部运行) (与 类对象 相似 )
也就是说 fs =
f3 ,f4 ,f5 分别等于fs里的 'lambda : 3*3'
所以f3'引爆'后等于 运行了return3*3
补充:
如果要用闭包实现 fs = (里面的lambda同样只是代指效果不是真实lambda)的话 ,代码应该这样改:
1 :fs.append(f) 中的 f 必须要'引爆'(成为单独的个体) ,
2 为了列表里的对象可以'引爆' , f的返回值必须是函数(def 或 lambda) ,
3 '个体'要保存有具体的值 ,而不是对外部的引用
其中第二点和第三点的结合 应该 才是闭包? 也就是说 f才是闭包函数 count不是…
例如:
def count():
fs = []
for i in range(1, 4):
def f():
arg =i #这句是为了让 arg 变为 f函数内部的值 ,而不是默认用 i的引用 or 如下
def f2(): #指 内部arg变量的值 等于 外部 i的值 (i 得是单个值(或独立的类实例) ,而不能是序列(类对象) ,否则arg也只能是个引用(会影响其他的引用))
return arg * arg
return f2
fs.append(f())
return fs
f1 ,f2 ,f3 = count()#f1() = 1 ,f2() = 4 ,f3() = 9
方式1返回的是列表,列表能加括号引用么,,不能
方式2列表3个元素,2个元素不能拆包
方式3因为数目一致,所以可以 楼上正解 塔利班 发表于 2018-11-4 15:01
方式1返回的是列表,列表能加括号引用么,,不能
方式2列表3个元素,2个元素不能拆包
方式3因为数目一致 ...
根据程序的情况,为什么不是 1,4,9的列表,而是9,9,9的列表呢?没有看懂运行的机理! 添加的是函数地址,当调用参数i的时候已经是i=3
如果添加的是f(),实时调用i返回就是1,4,9了 丨游戏灬需要 发表于 2018-11-17 18:38
1 ,f1 = count() ,但def count 的返回值是fs (是列表) ,所以报错说'列表对象
不能用"()"来"引爆"' #由于函 ...
涉及到本质了,这是python 基础部分最难的地方了。有点像c 里面的指针
页:
[1]