鱼C论坛

 找回密码
 立即注册
查看: 4774|回复: 21

[已解决]求lambda如何跟for in range搭配

[复制链接]
发表于 2021-1-26 14:47:31 | 显示全部楼层 |阅读模式

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

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

x
各位大佬,请问怎么理解f = [lambda : x for x in range(3) ]这个代码呀,不知道分析的先后顺序是什么,谢谢解答
最佳答案
2021-1-26 14:58:27
加个括号可能好理解点:
  1. f = [(lambda : x) for x in range(3) ]
复制代码


展开写就是这样:
  1. f = []
  2. for x in range(3):
  3.     def lambdax():
  4.         return x
  5.     f.append(lambdax)
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2021-1-26 14:58:27 From FishC Mobile | 显示全部楼层    本楼为最佳答案   
加个括号可能好理解点:
  1. f = [(lambda : x) for x in range(3) ]
复制代码


展开写就是这样:
  1. f = []
  2. for x in range(3):
  3.     def lambdax():
  4.         return x
  5.     f.append(lambdax)
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-1-26 16:09:46 | 显示全部楼层
hrp 发表于 2021-1-26 14:58
加个括号可能好理解点:

三个值都是2,为什么不是0,1,2呢?
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-1-26 16:18:15 From FishC Mobile | 显示全部楼层
123Marchapril 发表于 2021-1-26 16:09
三个值都是2,为什么不是0,1,2呢?

因为循环到最后x的值是2,所以后面调用列表中的函数,返回x就是返回2
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-1-26 16:41:20 | 显示全部楼层
  1. >>> f = []
  2. >>> for x in range(3):
  3.     def lambdax():
  4.         return x
  5.     f.append(lambdax)
复制代码


这个,当x等于0的时候,开始往f列表里插入数值,这时候就要执行lambdax程序,程序返回为x,此时x=0,那插入的数值就是0,我是哪里想错了吗?不好意思,我比较笨
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-1-26 16:42:02 | 显示全部楼层
hrp 发表于 2021-1-26 16:18
因为循环到最后x的值是2,所以后面调用列表中的函数,返回x就是返回2
  1. >>> f = []
  2. >>> for x in range(3):
  3.     def lambdax():
  4.         return x
  5.     f.append(lambdax)
复制代码


这个,当x等于0的时候,开始往f列表里插入数值,这时候就要执行lambdax程序,程序返回为x,此时x=0,那插入的数值就是0,我是哪里想错了吗?不好意思,我比较笨
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-1-26 16:52:40 From FishC Mobile | 显示全部楼层
123Marchapril 发表于 2021-1-26 16:42
这个,当x等于0的时候,开始往f列表里插入数值,这时候就要执行lambdax程序,程序返回为x,此时x=0, ...

f.append(lambdax)时候lambdax并没有被执行哈,插入的是函数lambdax的内存地址
f.append(lambdax())才是插入lambdax的返回值
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-1-26 17:00:17 | 显示全部楼层
本帖最后由 逃兵 于 2021-1-26 17:01 编辑
123Marchapril 发表于 2021-1-26 16:42
这个,当x等于0的时候,开始往f列表里插入数值,这时候就要执行lambdax程序,程序返回为x,此时x=0, ...


lambda函数的返回值是x
你修改了x的值就会影响lambda的值
在这里面,x的最终值是2(range(3)),所以所有的lambda函数都指向2
你在程序的末尾写个x=10的话,所有的lambda都会指向10了

  1. f = []
  2. for x in range(3):
  3.     def lambdax():
  4.         return x
  5.     f.append(lambdax)

  6. x = 10
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-1-26 18:43:26 | 显示全部楼层
本帖最后由 kogawananari 于 2021-1-26 18:45 编辑
  1. >>> import functools
  2. >>> g = [functools.partial(lambda x:x,x) for x in range(3)]
  3. >>> g[0]()
  4. 0
  5. >>> g[1]()
  6. 1
  7. >>> g[2]()
  8. 2
  9. >>>
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-1-26 18:50:30 | 显示全部楼层
说白了就是 你以为for循环的子句有作用域 然而并没有    想要f[0]()输出0,f[1]()输出1 是需要有作用域的 java是有这个作用域的 python没有 所以得嵌套函数来实现
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-1-26 21:10:30 | 显示全部楼层
hrp 发表于 2021-1-26 16:52
f.append(lambdax)时候lambdax并没有被执行哈,插入的是函数lambdax的内存地址
f.append(lambdax())才是 ...

您好,冒昧的打扰了,对于这个代码,我分析一下我的思路您看看对吗?
  1. >>> q = []
  2. >>> for x in range(3):
  3.         def lambdax():
  4.                 return x
  5.         q.append(lambdax)

  6.        
  7. >>> q[0]
  8. <function lambdax at 0x0000000002DA7310>
  9. >>> q[0]()
  10. 2
  11. >>> q[1]()
  12. 2
  13. >>> q[2]()
  14. 2
  15. >>> q[3]()
复制代码


首先由于q是一个列表,那我想看看列表第一项是什么,于是我输入q[0],然后系统提示我有未执行的函数,(我是把<function lambdax at 0x0000000002DA7310>这样的提示看做还有未执行的函数,不知道对不对),然后既然提示我有未执行的函数,于是我就加上(),然后发现“q[0]()”“q[1]()”“q[2]()”的值都为2,于是我就想是不是这样的:

在执行for x in range(3)的时候:
当x = 0时,列表q=[lambdax]            
当x = 1时,列表q=[lambdax,lambdax]
当x = 2时,列表q=[lambdax,lambdax,lambdax]
#这里的lambdax并不是提现在列表中真正的数值,而是作为未执行函数占一个地方(是吗?)

于是我输入q[0](),此时q=[lambdax] 中的函数lambdax开始执行,由于x的最终值落在了x=2上(这里其实还不是很懂)。所以函数lambdax的返回值都是2(包括q[1]()和q[2]()),也就是q=[2,2,2],所以以上的程序运行过程就是这样吗?我还有一个疑惑就是q=[2,2,2]怎么显示出来?







小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-1-26 21:13:12 | 显示全部楼层
逃兵 发表于 2021-1-26 17:00
lambda函数的返回值是x
你修改了x的值就会影响lambda的值
在这里面,x的最终值是2(range(3)),所以所 ...

老哥,您好,您说的x的最终值是2,是因为是f.append(lambdax)中的lambdax没带括号的缘故,所以只取最后一个值x=2吗?
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-1-26 21:37:35 | 显示全部楼层
kogawananari 发表于 2021-1-26 18:50
说白了就是 你以为for循环的子句有作用域 然而并没有    想要f[0]()输出0,f[1]()输出1 是需要有作用域的 j ...

所以a=[lambda:x for x in range(3)]中的“for x in range(3)”就可以视为x=3?是吗?
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-1-26 22:09:00 From FishC Mobile | 显示全部楼层
本帖最后由 hrp 于 2021-1-26 22:45 编辑
123Marchapril 发表于 2021-1-26 21:10
您好,冒昧的打扰了,对于这个代码,我分析一下我的思路您看看对吗?




像<function lambdax at 0x0000000002DA7310>这样的字符串是Python中用于表示函数对象的字符串。你说它是未执行的函数不正确(函数是可以反复调用的,不是一次性的),你想象中的  未执行、已执行  应该是:函数对象、函数返回值。

当你输入q[0](),相当于执行q里的第一个函数:lambdax(),因为它返回x,这时它就开始去找x的值,由于之前for循环已经循环结束,最后一次循环x的值被for赋值2,所以lambdax找到了2,返回2。

要让q显示[2,2,2]也简单,把q中的函数都调用一遍,拿它们的返回值就行了:q=[i() for i in q]
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-1-26 23:09:53 | 显示全部楼层
本帖最后由 123Marchapril 于 2021-1-26 23:14 编辑
hrp 发表于 2021-1-26 22:09
像这样的字符串是Python中用于表示函数对象的字符串。你说它是未执行的函数不正确(函数是可以反复调用 ...


非常感谢您,我再问最后一次哈:
a = [ lambda : x for x in range(30)]
这里面的for x in range(3)就直接默认成x = 2就可以了吗?
什么时候for i  in range(n+1)可以直接看做 i = n
什么时候考虑i = 0时怎样怎样,i = 1时怎样怎样,...i=n时怎样怎样啊
主要是我觉得for  i in range():后面带一个冒号。所以我有时候会觉得  i  = 0 的时候进行一次走程序,i  =  1的时候走一次程序,而今天这个for x in range(3) ,直接取x=3弄得我不太明白了
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-1-27 01:49:15 | 显示全部楼层
123Marchapril 发表于 2021-1-26 21:37
所以a=[lambda:x for x in range(3)]中的“for x in range(3)”就可以视为x=3?是吗?

你这个问题在别的编程语言里也有  
在JS(es5)里面 for循环也不拥有作用域 在for循环里面声明的变量是外层变量
代码你应该看得懂 编程语言都是互通的
  1. function foo(){
  2.     var arr = [];
  3.     for(var i = 0;i<10;i++){
  4.         arr[i] = function(){
  5.             console.log(i)
  6.         }
  7.     }
  8.     return arr
  9. }
  10. var mylist = foo();//mylist是一个存了10个函数的数组
  11. //此时mylist数组里的每个函数打印出来都会是10
复制代码

你需要函数能依次打印0到9 就要这么写
  1. function foo(){
  2.     var arr = [];
  3.     for(var i = 0;i < 10;i++){
  4.         arr[i] = (function(j){
  5.             return function(){
  6.                 console.log(j)
  7.             }
  8.         })(i)
  9.     }
  10.     return arr
  11. }
  12. var mylist = foo();
  13. //此时mylist数组里的每个函数打印出来就是对应的i的值
复制代码


同理 python 你的函数数组现在是 因为无论列表生成式还是for冒号缩进 都是没有作用域的
只有function(class)有作用域
  1. >>> q[0]()
  2. 2
  3. >>> q[1]()
  4. 2
  5. >>> q[2]()
  6. 2
复制代码

修改成我这种双层函数
  1. >>> import functools
  2. >>> g = [functools.partial(lambda x:x,x) for x in range(3)]
  3. >>> g[0]()
  4. 0
  5. >>> g[1]()
  6. 1
  7. >>> g[2]()
  8. 2
复制代码

就可以了
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-1-27 02:07:30 | 显示全部楼层
如果不用functools.partial  那就得像下面这样

  1. >>> g = [(lambda i : (lambda :i))(i) for i in range(3)]
  2. >>> g[2]()
  3. 2
  4. >>> g[1]()
  5. 1
  6. >>> g[0]()
  7. 0
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-1-27 10:25:08 From FishC Mobile | 显示全部楼层
123Marchapril 发表于 2021-1-26 23:09
非常感谢您,我再问最后一次哈:
a = [ lambda : x for x in range(30)]
这里面的for x in range(3) ...
这里面的for x in range(3)就直接默认成x = 2就可以了吗?

不是这个意思,x在每次循环中,肯定是分别是x=0、x=1、x=2,但要问循环结束后,x的值是多少?那肯定是最后一次给x赋值x=2。

什么时候for i  in range(n+1)可以直接看做 i = n

range是左闭右开的原则(包含左边的参数,不包含右边的参数),range(3)把省略的起始参数补上就是range(0, 3),它包含0、1、2三个。

什么时候考虑i = 0时怎样怎样,i = 1时怎样怎样,...i=n时怎样怎样啊

在循环进行时。循环结束后i当然只等于最后一个值。

主要是我觉得for  i in range():后面带一个冒号。所以我有时候会觉得  i  = 0 的时候进行一次走程序,i  =  1的时候走一次程序,而今天这个for x in range(3) ,直接取x=3弄得我不太明白了

纠正一下,是x=2。
你的想法是对的,但是直接取x=2那是因为for循环内f.append(lambdax)时lambdax并不关心x的值是什么,只是单纯的插入lambdax这个函数对象,最后q[0]()时已经出了for循环的范围了(也就是q[0]()之前循环就已经结束了),这时候x当然是最后一次循环的值x=2。

这些都是很基础的for循环、range知识。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-1-27 12:40:47 | 显示全部楼层
hrp 发表于 2021-1-27 10:25
不是这个意思,x在每次循环中,肯定是分别是x=0、x=1、x=2,但要问循环结束后,x的值是多少?那肯定是 ...

谢谢你哈。我会继续加强小甲鱼课程的学习
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-1-29 16:24:36 | 显示全部楼层
hrp 发表于 2021-1-27 10:25
不是这个意思,x在每次循环中,肯定是分别是x=0、x=1、x=2,但要问循环结束后,x的值是多少?那肯定是 ...

不好意思,我又有一个小疑问,a = [lambda :x for x in range(2)],是怎么体现"append"这个元素的?
就是我的意思是,如果x = 0,a=[lambda :x],x = 1,a=[lambda :x],x = 2,a=[lambda :x],那显然列表a里面只有一个元素呀,但是最后是有三个,所以a = [lambda :x for x in range(2)],是怎么体现"append"这个元素的?
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-6-28 04:09

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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