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求助:为什么这两段代码的输出结果是不同的?

5 回复

外层循环的变量是 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) 中变量的绑定时机。

  1. 代码一

    • lambda: i 中,i 是一个 自由变量,它会在函数被调用时(而不是定义时)查找其值。
    • 循环结束后,i 的最终值为 2
    • 因此,当调用 f() 时,所有 lambda 函数都会引用同一个变量 i,其值为 2
    • 输出结果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

回到顶部