鱼C论坛

 找回密码
 立即注册
查看: 1267|回复: 13

[已解决]《第20讲视频》关于闭包函数的疑问,求解答

[复制链接]
发表于 2018-5-14 20:59:04 | 显示全部楼层 |阅读模式

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

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

x
闭包函数.png 1.png

问题如下,待大佬们用通俗易懂的语言解答:

(1)图一中最后一排为什么要单独打出fun2()这个函数?我试了下如果不写这句,fun2()正在被调用这句话就显示不出来。这是为什么呢,明明已经定义了fun2啊
(2)对于第二个图,通过小甲鱼的讲解我已经知道FunY(y)是闭包函数,它的表达式是x*y,最后一步return FunY我不明白为什么要这样,它和外部函数FunX有什么关系?
(3)最后一步return FunY如果加括号写成return FunY()就会报错,为什么呢?意思只能返回一个值,返回函数就不行?
(4)i=FunX(8)意思参数小x=8,那么i(5)=FunX(8)(5)=8*5=40,可是x*y这个表达式前面是属于 FunY的,这里是FunX(8)(5),为什么还可以执行8*5的操作呢

零基础自学到这里表示有点晕了,感觉理解上绕进了死胡同,希望能有大神帮忙解答一下,谢谢了!
最佳答案
2018-5-16 08:39:44
本帖最后由 thexiosi 于 2018-5-17 16:16 编辑

没事,慢慢来,我们一个一个问题说:

(1)中意思在print下面再打一次fun2()就是调用函数的意思吗?小甲鱼平时说的调用函数他都是定义完了函数,在全局里打这个函数名,这个叫调用啊。
我们再看一遍 fun1()函数 代码: 老师说的没错,函数定义完毕后才能调用。 fun1()里已经完整定义了fun2() 且 是在fun2()定义结束后(调用它的子函数),执行的调用,因此调用有效。如果把fun2()提到def fun2()前,会报错。
  1. def fun1():
  2.   print('fun1()')
  3.   def fun2():
  4.       print('fun2()')
  5.   fun2()
复制代码


(3)中你说报错的原因是没带参数,但是我写的是return FunY(y)也是报错,括号里不是空白,有写参数y,只有写单独return FunY不会报错。
return FunY()会报错,return FunY(y) 肯定也会报错。因为他们都无法被程序正常识别:return FunY(), 会提示你缺失参数;return FunY(y),会提示你 y没有被定义,因为变量y定义在FunY函数中,FunX不知道y到底是什么。这段代码,有效return方式就是:return FunY ,返回函数地址



(4)中“因为最终返回了FunY()函数的地址,因此使得FunX(8)(5)有效”我还是没理解到意思,什么叫函数的地址?地址?这个因果关系,使得FunX(8)(5)有效没明白,能再讲下吗。万分感激
举个栗子
  1. def fun1(x):
  2.     x = x * 5
  3.     return x
复制代码

>>> fun1  #返回函数的地址
<function fun1 at 0x0000000002FB8268>
>>> fun1(5) #正常调用函数
25
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-5-14 21:03:53 | 显示全部楼层
图片加载顺序反了,图一应该是第二个图,第二个图是上面那个
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-5-15 07:57:07 | 显示全部楼层
本帖最后由 ABC23 于 2018-5-15 10:36 编辑

闭包时用来写decorator地。
================

>>> def timer(func):
        cnt = 1
        def inner():
                nonlocal cnt
                print('cnt =', cnt)
                from time import time
                start = time()
                func()
                t = time() - start
                print('t = ', t)
                cnt += 1
        return inner

>>> @timer
def foo():
        for i in range(100000000):
                pass

>>> foo()
cnt = 1
t =  2.773348808288574
>>> foo()
cnt = 2
t =  2.7720999717712402
>>> foo()
cnt = 3
t =  2.7723278999328613
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2018-5-15 09:23:41 | 显示全部楼层
(1)图一中最后一排为什么要单独打出fun2()这个函数?我试了下如果不写这句,fun2()正在被调用这句话就显示不出来。这是为什么呢,明明已经定义了fun2啊
#仅仅进行了定义,但是没调用;只有调用了,才会有函数返回

(2)对于第二个图,通过小甲鱼的讲解我已经知道FunY(y)是闭包函数,它的表达式是x*y,最后一步return FunY我不明白为什么要这样,它和外部函数FunX有什么关系?
#return FunY,返回函数的地址。需要和你的问题(4)结合起来理解

(3)最后一步return FunY如果加括号写成return FunY()就会报错,为什么呢?意思只能返回一个值,返回函数就不行?
#return FunY()就会报错的原因:缺失参数,因为定义的是 FunY(y)、带参数

(4)i=FunX(8)意思参数小x=8,那么i(5)=FunX(8)(5)=8*5=40,可是x*y这个表达式前面是属于 FunY的,这里是FunX(8)(5),为什么还可以执行8*5的操作呢
#和问题(2)一起理解,因为最终返回了FunY()函数的地址,因此使得FunX(8)(5)有效 。相当于FunY(5) (其中x=8)
#可以分解来看
--FunX(8)(5),先看FunX(8),他返回FunY (x赋值为8)
--因为FunX(8)(5)相当于 FunY(5) (x赋值为8)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2018-5-15 23:39:37 | 显示全部楼层
thexiosi 发表于 2018-5-15 09:23
(1)图一中最后一排为什么要单独打出fun2()这个函数?我试了下如果不写这句,fun2()正在被调用这句话就显 ...

谢谢解答,还有些不懂,(1)中意思在print下面再打一次fun2()就是调用函数的意思吗?小甲鱼平时说的调用函数他都是定义完了函数,在全局里打这个函数名,这个叫调用啊。(3)中你说报错的原因是没带参数,但是我写的是return FunY(y)也是报错,括号里不是空白,有写参数y,只有写单独return FunY不会报错。(4)中“因为最终返回了FunY()函数的地址,因此使得FunX(8)(5)有效”我还是没理解到意思,什么叫函数的地址?地址?这个因果关系,使得FunX(8)(5)有效没明白,能再讲下吗。万分感激
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-5-16 08:39:44 | 显示全部楼层    本楼为最佳答案   
本帖最后由 thexiosi 于 2018-5-17 16:16 编辑

没事,慢慢来,我们一个一个问题说:

(1)中意思在print下面再打一次fun2()就是调用函数的意思吗?小甲鱼平时说的调用函数他都是定义完了函数,在全局里打这个函数名,这个叫调用啊。
我们再看一遍 fun1()函数 代码: 老师说的没错,函数定义完毕后才能调用。 fun1()里已经完整定义了fun2() 且 是在fun2()定义结束后(调用它的子函数),执行的调用,因此调用有效。如果把fun2()提到def fun2()前,会报错。
  1. def fun1():
  2.   print('fun1()')
  3.   def fun2():
  4.       print('fun2()')
  5.   fun2()
复制代码


(3)中你说报错的原因是没带参数,但是我写的是return FunY(y)也是报错,括号里不是空白,有写参数y,只有写单独return FunY不会报错。
return FunY()会报错,return FunY(y) 肯定也会报错。因为他们都无法被程序正常识别:return FunY(), 会提示你缺失参数;return FunY(y),会提示你 y没有被定义,因为变量y定义在FunY函数中,FunX不知道y到底是什么。这段代码,有效return方式就是:return FunY ,返回函数地址



(4)中“因为最终返回了FunY()函数的地址,因此使得FunX(8)(5)有效”我还是没理解到意思,什么叫函数的地址?地址?这个因果关系,使得FunX(8)(5)有效没明白,能再讲下吗。万分感激
举个栗子
  1. def fun1(x):
  2.     x = x * 5
  3.     return x
复制代码

>>> fun1  #返回函数的地址
<function fun1 at 0x0000000002FB8268>
>>> fun1(5) #正常调用函数
25
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-5-16 10:52:51 | 显示全部楼层
thexiosi 发表于 2018-5-16 08:39
没事,慢慢来,我们一个一个问题说:

(1)中意思在print下面再打一次fun2()就是调用函数的意思吗?小 ...

好像有点模模糊糊的明白了,您看我这样说表达的对不对哈。首先,我们在全局里只能调用FunX(x)这个最外部的函数,不能出现FunY的函数。然后对于FunY(y)这个函数它的参数是y,表达式可以看成我们数学的FunY(y)=x*y,最后对于这整个函数我们只看最后一步只看结果不看过程的话,它就是对于FunX(x)函数来说要它返回FunY这个函数地址,等量代换,去找FunY的函数地址就是FunY(y)=x*y,因此等量代换FunX(x)=x*y。。。是这个意思吗大神?但是听了你的解答,FunY不带任何括号和参数,这样单独的存在就叫地址是把?但是我去找它的函数地址,上面出现的只有FunY(y)=x*y,这里的有FunY(y)是带有(y)的,那就不叫地址哦?我就找不到FunY的函数地址了呀?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-5-16 11:59:39 | 显示全部楼层
leftjay 发表于 2018-5-16 10:52
好像有点模模糊糊的明白了,您看我这样说表达的对不对哈。首先,我们在全局里只能调用FunX(x)这个最外 ...

嗯 可以这样理解的。建议过两天之后(先让大脑休息下),你再重新思考下,应该会清楚很多

return FunY #返回函数地址
FunY(y) #正常的函数调用:先获取函数地址,再进行具体的函数调用
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-5-16 15:00:41 | 显示全部楼层
thexiosi 发表于 2018-5-16 11:59
嗯 可以这样理解的。建议过两天之后(先让大脑休息下),你再重新思考下,应该会清楚很多

return FunY ...

恩恩非常感谢你哈!好像真的明白了,return FunY是针对于外部函数FunX(x)的,程序收到命令就返回去找FunY的函数地址,在第二排找到了FunY(y),然后这个可以看成是两个东西的构成,不看(y)那就是找到了外面FunY这个地址,然后带上(y)就是让你在找到了地址后执行它的命令也就是x*y,然后把x*y的数值反馈给FunY,再由FunY返回给FunX(x)这个函数。是把?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-5-16 16:03:37 | 显示全部楼层
thexiosi 发表于 2018-5-16 11:59
嗯 可以这样理解的。建议过两天之后(先让大脑休息下),你再重新思考下,应该会清楚很多

return FunY ...

大神,最后一个问题,前面你写的“return FunY()会报错,return FunY(y) 肯定也会报错。因为他们都缺失参数,前者缺失 x,y ; 后者缺失 x。这段代码,有效return方式就是:return FunY ,返回函数地址”这段话是不是有问题啊?return FunY(y)和return FunY(x*y)都报错,原因是y没被定义,而不是说缺乏参数呢。但是FunY是函数名,也是要返回第二排def funY(y)的,然后返回x*y,那这里同样也有小y,怎么就没有红字说它没被定义呢。这个地方我始终想不通。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-5-16 16:26:38 | 显示全部楼层
本帖最后由 thexiosi 于 2018-5-16 16:36 编辑
leftjay 发表于 2018-5-16 16:03
大神,最后一个问题,前面你写的“return FunY()会报错,return FunY(y) 肯定也会报错。因为他们都缺失参 ...


实在不好意思,我之前说的不准确

这种情况是错误的:

  1. def FunX(x):
  2.     def FunY(y):
  3.         return x * y
  4.     return FunY(y)
复制代码

会提示你y没有定义,最好还是返回函数地址 return FunY,这样不会出错。
>>> FunX(2)(4)
NameError: name 'y' is not defined

如下这种情况是正确的:

  1. def FunX(x):
  2.     def FunY(y):
  3.         return x * y
  4.     return FunY(2)
复制代码


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

使用道具 举报

 楼主| 发表于 2018-5-17 15:37:41 | 显示全部楼层
thexiosi 发表于 2018-5-16 16:26
实在不好意思,我之前说的不准确

这种情况是错误的:

恩,明白。当我们写return funY(y)不是会报错吗,说y没被定义,最后问一句这个y没被定义,是程序运行到哪一步感受到的y没被定义呢,是第几排的y?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-5-17 16:04:33 | 显示全部楼层
leftjay 发表于 2018-5-17 15:37
恩,明白。当我们写return funY(y)不是会报错吗,说y没被定义,最后问一句这个y没被定义,是程序运行到 ...

运行到 return FunY(y)时 ,程序识别不了y,弹出报错提示

原因分析:return语句 是在FunX(x)函数中定义的,它并不清楚y到底是什么,因为变量y的作用域仅在FunY(y)中,这就是闭包。因此,这种情况下,通过return FunY是最稳妥的,因为程序知道FunY的函数地址

不好意思,由于个人能力有限,之前答的并不是很清晰,希望没有误导你。另外,我看到 你另外开了帖子,大牛回答的非常好,你可以好好参考下
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-5-17 16:51:44 | 显示全部楼层
thexiosi 发表于 2018-5-17 16:04
运行到 return FunY(y)时 ,程序识别不了y,弹出报错提示

原因分析:return语句 是在FunX(x)函数中定 ...

好的,非常感谢你的耐心帮助哈!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-5-18 10:04

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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