鱼C论坛

 找回密码
 立即注册
查看: 2923|回复: 11

[已解决]第20课 习题6闭包问题

[复制链接]
发表于 2016-4-15 21:52:37 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 bp2018 于 2016-6-6 21:20 编辑

题目是:

def funX():
    x = 5
    def funY():
        nonlocal x
        x += 1
        return x
    return funY

a = funX()
print(a())
print(a())
print(a())

会打印:
6
7
8

给出的解释是:a=funX(),a没有重新被赋值,因此FunX()没被释放,因此局部变量x没有被初始化。

那么改为a=funX,如下:
def funX():
    x = 5
    def funY():
        nonlocal x
        x += 1
        return x
    return funY

a = funX
print(a()())
print(a()())
print(a()())

按照上述概念a也没有被重新赋值(不太懂?),为何打印结果是下面的数字呢?
6
6
6

感觉有点晕,请高手解答,谢谢!


最佳答案
2016-4-16 11:01:45
bp2018 发表于 2016-4-15 23:52
按照你的方法又看了看,还是定义a=funX,最后无论是输出id(a),或id(a()) 或 id(a()()), id是一样的?
...

a=funX, 这时候a指向的是函数对象funX,也就是:
def funX():
    x = 5
    def funY():
        nonlocal x
        x += 1
        return x
    return funY
注意:这时候只是用a指向函数对象,并没有调用,所以还没有返回funY这个函数对象.

而加了括号的a()是调用上面那个函数对象,这个函数返回另一个函数对象funY,每调用一次a()就返回1个新的函数对象,
fun1 = a()
fun2 = a()
fun3 = a()

print(id(fun1), id(fun2). id(fun3))
print(fun1 == fun2 == fun3)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2016-4-15 22:51:57 | 显示全部楼层

a=funx,这时函数还没有执行啊,print的时候才开始执行
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-4-15 23:15:08 | 显示全部楼层
在python中一切皆对象,函数也是对象,闭包函数返回的也是一个函数对象
在第一个例子中funX()只被调用了1次,也就是说只返回了1个函数对象,用变量a指向这个函数对象,可以在每个print后面跟踪一下id(a),可以看到a始终指向同1个函数对象,并没有改变过
再看看看第2个例子,a=funX,而a()被调用了3次,也就是返回的是3个不同的函数对象,实际上那段代码等同于:
fun1 = a()
print(fun1())
fun2 = a()
print(fun2())
fun3 = a()
print(fun3())
再用id()函数看一下,fun1,fun2,fun3是3个不同的函数对象.
好比你定义了2个内容相同的函数:
def f1(x):
    return x
def f2(x):
    return x
print(id(f1), id(f2))
可以看到f1和f2虽然内容相同,但却是两个不同的函数对象.

评分

参与人数 1荣誉 +3 鱼币 +5 收起 理由
~风介~ + 3 + 5 支持楼主!

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-4-15 23:27:46 | 显示全部楼层
如果还想深入了解闭包,可以看一下关于python闭包函数的__closure__属性,闭包的环境变量就放在这个属性中,在你的第一个例子中,可以用a.__closure__[0].cell_contents查看环境变量x的值
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-4-15 23:42:11 | 显示全部楼层
谢谢搂上2位,我再琢磨琢磨!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-4-15 23:52:27 | 显示全部楼层
本帖最后由 bp2018 于 2016-4-15 23:55 编辑
挥舞乾坤 发表于 2016-4-15 23:15
在python中一切皆对象,函数也是对象,闭包函数返回的也是一个函数对象
在第一个例子中funX()只被调用了1次, ...


按照你的方法又看了看,还是定义a=funX,最后无论是输出id(a),或id(a()) 或 id(a()()), id是一样的?

前面代码一样如下:
def funX():
    x = 5
    def funY():
        nonlocal x
        x += 1
        return x
    return funY


后面三者,print结果都是6,6,6 id相同
a = funX
print(a()(),id(a()))
print(a()(),id(a()))
print(a()(),id(a()))
a = funX
print(a()(),id(a))
print(a()(),id(a))
print(a()(),id(a))
a = funX
print(a()(),id(a()()))
print(a()(),id(a()()))
print(a()(),id(a()()))

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-4-16 00:12:17 | 显示全部楼层
funx()是内置函数 funx是变量 a=funx()和a=funx 完全不一样的两个概念吧 我也是新手 不知道对不对
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-4-16 11:01:45 | 显示全部楼层    本楼为最佳答案   
bp2018 发表于 2016-4-15 23:52
按照你的方法又看了看,还是定义a=funX,最后无论是输出id(a),或id(a()) 或 id(a()()), id是一样的?
...

a=funX, 这时候a指向的是函数对象funX,也就是:
def funX():
    x = 5
    def funY():
        nonlocal x
        x += 1
        return x
    return funY
注意:这时候只是用a指向函数对象,并没有调用,所以还没有返回funY这个函数对象.

而加了括号的a()是调用上面那个函数对象,这个函数返回另一个函数对象funY,每调用一次a()就返回1个新的函数对象,
fun1 = a()
fun2 = a()
fun3 = a()

print(id(fun1), id(fun2). id(fun3))
print(fun1 == fun2 == fun3)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-4-16 15:16:03 | 显示全部楼层
挥舞乾坤 发表于 2016-4-16 11:01
a=funX, 这时候a指向的是函数对象funX,也就是:

注意:这时候只是用a指向函数对象,并没有调用,所以还没 ...

谢谢!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-4-19 16:08:23 | 显示全部楼层
谢谢答主指点
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-4-22 13:36:38 | 显示全部楼层
谢谢大神的解答!!!!!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-7-18 12:55:36 | 显示全部楼层
谢谢大神的解答!!!!!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-22 17:24

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表