鱼C论坛

 找回密码
 立即注册
查看: 3992|回复: 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
加个括号可能好理解点:
f = [(lambda : x) for x in range(3) ]

展开写就是这样:
f = []
for x in range(3):
    def lambdax():
        return x
    f.append(lambdax)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

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

展开写就是这样:
f = []
for x in range(3):
    def lambdax():
        return x
    f.append(lambdax)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

三个值都是2,为什么不是0,1,2呢?
想知道小甲鱼最近在做啥?请访问 -> 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
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

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

使用道具 举报

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

这个,当x等于0的时候,开始往f列表里插入数值,这时候就要执行lambdax程序,程序返回为x,此时x=0,那插入的数值就是0,我是哪里想错了吗?不好意思,我比较笨
想知道小甲鱼最近在做啥?请访问 -> 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的返回值
想知道小甲鱼最近在做啥?请访问 -> 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了
f = []
for x in range(3):
    def lambdax():
        return x
    f.append(lambdax)

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

使用道具 举报

发表于 2021-1-26 18:43:26 | 显示全部楼层
本帖最后由 kogawananari 于 2021-1-26 18:45 编辑
>>> import functools
>>> g = [functools.partial(lambda x:x,x) for x in range(3)]
>>> g[0]()
0
>>> g[1]()
1
>>> g[2]()
2
>>>
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

使用道具 举报

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

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

        
>>> q[0]
<function lambdax at 0x0000000002DA7310>
>>> q[0]()
2
>>> q[1]()
2
>>> q[2]()
2
>>> 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]怎么显示出来?







想知道小甲鱼最近在做啥?请访问 -> 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吗?
想知道小甲鱼最近在做啥?请访问 -> 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?是吗?
想知道小甲鱼最近在做啥?请访问 -> 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]
想知道小甲鱼最近在做啥?请访问 -> 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弄得我不太明白了
想知道小甲鱼最近在做啥?请访问 -> 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循环里面声明的变量是外层变量
代码你应该看得懂 编程语言都是互通的
function foo(){
    var arr = [];
    for(var i = 0;i<10;i++){
        arr[i] = function(){
            console.log(i)
        }
    }
    return arr
}
var mylist = foo();//mylist是一个存了10个函数的数组
//此时mylist数组里的每个函数打印出来都会是10
你需要函数能依次打印0到9 就要这么写
function foo(){
    var arr = [];
    for(var i = 0;i < 10;i++){
        arr[i] = (function(j){
            return function(){
                console.log(j)
            }
        })(i)
    }
    return arr
}
var mylist = foo();
//此时mylist数组里的每个函数打印出来就是对应的i的值

同理 python 你的函数数组现在是 因为无论列表生成式还是for冒号缩进 都是没有作用域的
只有function(class)有作用域
>>> q[0]()
2
>>> q[1]()
2
>>> q[2]()
2
修改成我这种双层函数
>>> import functools
>>> g = [functools.partial(lambda x:x,x) for x in range(3)]
>>> g[0]()
0
>>> g[1]()
1
>>> g[2]()
2
就可以了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-1-27 02:07:30 | 显示全部楼层
如果不用functools.partial  那就得像下面这样
>>> g = [(lambda i : (lambda :i))(i) for i in range(3)]
>>> g[2]()
2
>>> g[1]()
1
>>> g[0]()
0
想知道小甲鱼最近在做啥?请访问 -> 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知识。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

谢谢你哈。我会继续加强小甲鱼课程的学习
想知道小甲鱼最近在做啥?请访问 -> 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"这个元素的?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-1-16 13:02

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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