Python求助:为什么这两段代码的输出结果是不同的?
首先,这样的 2 段代码
for i in range(1,10):
for j in range(0,i):
print(2**j,end=" ")
print("")
print("\n")
for i in range(1, 10):
for i in range(0, i, 1):
print(2**i,end=" “)
print(”")
print("\n")
输出均为
1
1 2
1 2 4
1 2 4 8
1 2 4 8 16
1 2 4 8 16 32
1 2 4 8 16 32 64
1 2 4 8 16 32 64 128
1 2 4 8 16 32 64 128 256
然后倒序输出
for i in range(1,10):
for i in range(-1+i,-1,-1):
print(2**i,end=" ")
print("")
print("\n")
for i in range(1, 10):
for k in range(-1 + i, -1, -1):
print(2**k,end=" “)
print(”")
print("\n")
输出结果都是
1
2 1
4 2 1
8 4 2 1
16 8 4 2 1
32 16 8 4 2 1
64 32 16 8 4 2 1
128 64 32 16 8 4 2 1
256 128 64 32 16 8 4 2 1
但是结合到一起
for i in range(1,10):
for j in range(0,i):
print(2**j,end=" ")
for k in range(-1+i,-1,-1):
print(2**k,end=" ")
print("")
print("\n")
for i in range(1, 10):
for i in range(0, i, 1):
print(2i,end=" ")
for i in range(-1 + i, -1, -1):
print(2i,end=" “)
print(”")
print("\n")
结果就变成了
1 1
1 2 2 1
1 2 4 4 2 1
1 2 4 8 8 4 2 1
1 2 4 8 16 16 8 4 2 1
1 2 4 8 16 32 32 16 8 4 2 1
1 2 4 8 16 32 64 64 32 16 8 4 2 1
1 2 4 8 16 32 64 128 128 64 32 16 8 4 2 1
1 2 4 8 16 32 64 128 256 256 128 64 32 16 8 4 2 1
1
1 2 1
1 2 4 2 1
1 2 4 8 4 2 1
1 2 4 8 16 8 4 2 1
1 2 4 8 16 32 16 8 4 2 1
1 2 4 8 16 32 64 32 16 8 4 2 1
1 2 4 8 16 32 64 128 64 32 16 8 4 2 1
1 2 4 8 16 32 64 128 256 128 64 32 16 8 4 2 1
Python求助:为什么这两段代码的输出结果是不同的?
外层循环的变量是 i
内层循环的变量也是 i
帖子标题:Python求助:为什么这两段代码的输出结果是不同的?
代码一:
def func1():
result = []
for i in range(3):
result.append(lambda: i)
return result
for f in func1():
print(f())
代码二:
def func2():
result = []
for i in range(3):
result.append(lambda x=i: x)
return result
for f in func2():
print(f())
问题分析:
这两段代码的核心区别在于 闭包(closure) 中变量的绑定时机。
-
代码一:
- 在
lambda: i中,i是一个 自由变量,它会在函数被调用时(而不是定义时)查找其值。 - 循环结束后,
i的最终值为2。 - 因此,当调用
f()时,所有lambda函数都会引用同一个变量i,其值为2。 - 输出结果:
2 2 2
- 在
-
代码二:
- 在
lambda x=i: x中,i作为默认参数x的默认值。 - 默认参数的值在函数定义时(即循环的每一步)就被 绑定 了。
- 因此,每个
lambda函数捕获的是当前循环中i的瞬时值(0、1、2)。 - 输出结果:
0 1 2
- 在
关键点总结:
- 闭包延迟绑定:在代码一中,
i的值在调用时才确定,导致所有函数引用同一个最终值。 - 默认参数即时绑定:在代码二中,默认参数在定义时捕获了
i的当前值,实现了按预期输出。
一句话建议: 使用默认参数或 functools.partial 来捕获循环变量的当前值,避免闭包延迟绑定问题。
执行第一个 loop
for i in range(0, i, 1):
之后 i 的值变成了 i-1
所以第二个 loop
for i in range(-1 + i, -1, -1)
的-1 + i 的值就错了
多谢,明白了。就是外循环的变量 i,在内循环开始时,其实就相当于常量,也就是内循环的 i 和外循环的 i 不是同一个变量。 而 2 个内循环的 2 个 i,其实是同一个变量。这样理解对吧
所有的 i 都是同一个变量,关键其实是外层 loop 执行时 i 的值会被改写回来,要解释的话应该是
外层 loop
for i in range(1, 10)
生成一个[1, 2, …, 9]的 list,依次给 i 赋值,假设执行到 i=2,往下执行。
第一层 loop
for i in range(0, i, 1)
先解析 range(0, i, 1),此时 i 的值是外层 loop 传下来的 i 的值 2,之后生成了一个[0, 1]的 list,list 中的每个元素都会给 i 赋值,改变 i 的值,直到 loop 完,此时 i 的值为 1。
第二层 loop
for i in range(-1 + i, -1, -1)
同样解析 range(-1 + i, -1, -1),此时 i 的值是刚刚得到的 1,所以生成了一个[0]的 list,给 i 赋值
之后回到外层 loop,list 继续给 i 赋值成 3,继续运行。
官方说明
https://docs.python.org/dev/reference/compound_stmts.html#for
The for-loop makes assignments to the variables in the target list. This overwrites all previous assignments to those variables including those made in the suite of the for-loop:
for i in range(10):
print(i)
i = 5 # this will not affect the for-loop
# because i will be overwritten with the next
# index in the range

