Python中for循环与直接赋值输出结果不一致,[12,13,14,15]和[20,21,22,23]为何不同?

def add(a, b):
return a + b

def test():
for r_i in range(4):
yield r_i

g = test()
#0 1 2 3

# g = (add(2, i) for i in g)
# g = (add(10, i) for i in g)
# print(list(g))
#[12, 13, 14, 15]

for n in [2, 10]:
# 0 1 2 3
# 2 1 2 3
g = (add(n, i) for i in g)
#第一次循环 n=2,i 第一次循环 0 相加结果 2 3 4 5
#第二次循环 n=10,i 第一次循环 2 相加结果 12 13 14 15
print(list(g))
#为啥输出[20, 21, 22, 23]
Python中for循环与直接赋值输出结果不一致,[12,13,14,15]和[20,21,22,23]为何不同?


21 回复

打印 add 的参数 a 和 b,可以发现 a 在循环的方式中始终是 10,也就是 n 引用的始终是最后一次循环 n 的值,这和直接传值的方式是不一样的。


我无法理解你的问题。

#1 如果用列表生成式就不会出现这种情况,因为生成器只有在被遍历时才会进行运算。

#2 列表生成式则会一次性进行所有的运算

换成列表生产式 g = [add(n, i) for i in g],for 和单独传值结果一致[12, 13, 14, 15],不明白是怎么推算出[20, 21, 22, 23],for 第二次循环会覆盖上次循环的值吧。

感觉是 python 语言的糟粕。。

如果遍历一次生成器表达式,那么 g 就没值了,生成器表达式 g = (add(n, i) for i in g) for i in g 不会遍历 g 么

#6 g 在第一次遍历时没值了,但是你又赋值给 g 了。。。

逐级遍历吧
比如一开始 g 是 0 1 2 3,第一次循环 的第一次遍历
2 1 2 3
2 3 2 3
2 3 4 3
2 3 4 5

这样理解对么

n 一直是 10 哇,结果应该是 10+10+i

10+10+i 是怎么来的呢

#8 不懂你在讲哪个方面了。。。
在循环的方式下,第一次循环时,g 的值为
(
add(2, 0),
add(2, 1),
add(2, 2),
add(2, 3)
)
第二次循环时,g 的值为
(
add(10, add(10, 0)),
add(10, add(10, 1)),
add(10, add(10, 2)),
add(10, add(10, 3))
)

原来如此,明白了,感谢

我记得叫 late binding 机制吧,两次计算的时候 n=10

你把 2 改成 None 或者字符串,你就发现问题了

g = (add(n, i) for i in g) 改成 g = [add(n, i) for i in g] 就达到要求了

整理如下,看理解对吗?

#总结:推导式有,列表推导式、字典推导式、集合推导式,没有元组推导式
#生成器表达式:(结果 for 变量 in 可迭代对象 if 条件) 生成器表达式可直接获取其对象,对象可直接使用 for 循环,生成器具有惰性机制

def add(a, b):
return a + b

def test():
for r_i in range(4):
yield r_i

g = test()
#0 1 2 3

# g = (add(2, i) for i in g)

#g 的值是
# (
# add(2, 0),
# add(2, 1),
# add(2, 2),
# add(2, 3)
# )

# g = (add(10, i) for i in g)

#g 的值是
# (
# add(10, add(2, 0)),
# add(10, add(2, 1)),
# add(10, add(2, 2)),
# add(10, add(2, 3))
# )
#遍历生成器开始运算输出结果
# print(list(g))
#输出[12, 13, 14, 15]

for n in [2, 10]:
# g = [add(n, i) for i in g] #列表生成式会一次性进行所有的运算
# 第一次循环 n=2,i 第一次循环 0 相加结果 2 3 4 5
# 第二次循环 n=10,i 第一次循环 2 相加结果 12 13 14 15

g = (add(n, i) for i in g) # 生成器表达式只有在被遍历时才会进行运算
#第一次循环 n=2,i 从 0 1 2 3 循环,因生成器具有惰性机制,n 并没有取对应值,只是指向对应内存地址,g 的值是
# (
# add(n, 0),
# add(n, 1),
# add(n, 2),
# add(n, 3)
# )
#第二次循环 n=10,i 从 add(2, 0) add(2, 1) add(2, 2) add(2, 3)循环,同理,g 的值是
# (
# add(n, add(n, 0)),
# add(n, add(n, 1)),
# add(n, add(n, 2)),
# add(n, add(n, 3))
# )
#for 循环完,系统会释放 n,释放之前 n 先取值,g 的值是
# (
# add(10, add(10, 0)),
# add(10, add(10, 1)),
# add(10, add(10, 2)),
# add(10, add(10, 3))
# )
#遍历生成器开始运算输出结果
print(list(g))
#输出[20, 21, 22, 23]

a = [1, 2]
a[1] = a
print(a[1])
补门一个问题
为啥结果是:
[1, […]]


因为 a[1]是 a 自己啊
所以会无限循环下去
你会发现 a[1], a[1][1], a[1][1][1]… 都是[1, […]]

#16

#13 说的准确一些,因为 lambda 表达式放在列表生成式也会出现这种现象,具体的讲解可以搜索关键词 late binding


a[1]=a
第一次 a=[1, [1, 2] ] 第二次 a=[1, [1, [1, 2] ] ] 第三次 a=[1, [1, [1, [1, 2] ] ] ]
这样理解对吗

回到顶部