Python中始终想不明白 a, b = b, a + b 到底是怎么工作的?

如下例:

class Fib(object):
    def __getitem__(self, n):
        a, b = 1, 1
        for x in range(n):
            a, b = b, a + b
        return a,b

f = Fib()

print(f[0])

输出为什么是(1,1),而不是( 1,2 )?后面那个 1 到底是怎么产生的?


Python中始终想不明白 a, b = b, a + b 到底是怎么工作的?

15 回复

list(range(0)) == []


这个写法是Python的“多重赋值”特性,核心在于赋值前先计算右侧所有表达式

看个例子就明白了:

a, b = 0, 1
for _ in range(5):
    a, b = b, a + b  # 关键在这里
    print(f"a={a}, b={b}")

执行过程:

  1. 计算右侧 ba + b 的值(此时用的是旧的a和b)
  2. 将计算好的值按顺序赋给左侧的a和b

以第一次循环为例:

  • 初始:a=0, b=1
  • 计算右侧:b=1, a+b=0+1=1
  • 赋值:a=1, b=1

这相当于:

temp = (b, a + b)  # 先打包成元组
a = temp[0]        # 再解包赋值
b = temp[1]

所以不会出现你担心的“a先被覆盖导致b计算错误”的情况。这是Python交换变量值的常用技巧,比用临时变量更简洁。

总结:右侧先计算完,再一次性赋值。

for x in range(0) ,所以后面的赋值语句没有跑。。。

a, b = b, a+b
完成的工作相当于
c = a
a = b
b = c+b

后面那个 1 难道不是你自己赋值的?
python<br>a, b = 1, 1<br>

range(0) 的结果就是空列表好嘛?根本没有跑进循环体啊

python<br>&gt;&gt;&gt; for i in range(0):<br>... print('进来了吗')<br>...<br>&gt;&gt;&gt; print(range(0))<br>[]<br>&gt;&gt;&gt;<br>




0 基础初学 python,可能有些理解欠缺,照你们这么说,我对 for 循环的理解有误?

拿 for x in range(3)举例,x 会分别赋值 0,1,2,也就是它会运行 3 次。
第一次:
a,b = b,a+b ---->(1,2)
第二次:
a,b = b,a+b ---->(2,3)
第三次:
a,b = b,a+b ---->(3,5)

那么,f[0]不是取第一次运算后的结果么?

f[0]等于f.__getitem__(0)

额,我们来数个数

range(3) 会赋值 0 1 2
range(2) 会赋值 0 1
range(1) 会赋值 0
range(0) 呢?



[/捂脸][/捂脸][/捂脸],恍然大悟!

f[0]不是取第一次运算的结果,而是取 n=0 时的结果,这么简单的逻辑,思考了两个下午都没思考透哈哈哈。

a, b = b, a+b
这个其实是元组赋值了,python 会自动把右边这种用逗号分开的格式作为元组, 例如:
>>> a = 1, 2
>>> type(a)
<class ‘tuple’>
>>> c, d = a
>>> c, d
(1, 2)
也就是这个语句大概上就是个语法糖, 右边是多个值赋值, 左边是元组。

你至少要给 n 赋个值吧

Fib 一般有个 if 吧

把这个 Fib 类转换成字节码可以看到,for 循环内部是这个样子的
5 22 LOAD_FAST 3 (b)
24 LOAD_FAST 2 (a)
26 LOAD_FAST 3 (b)
28 BINARY_ADD
30 ROT_TWO
32 STORE_FAST 2 (a)
34 STORE_FAST 3 (b)
36 JUMP_ABSOLUTE 18
>> 38 POP_BLOCK

可以看到按照 b, a, b 的顺序压栈,然后对栈顶的两个元素进行相加(即 a + b ),然后分别存到 b, a (这里故意写反,因为中间有一个 ROT_TWO 操作)。所以说白了,Python 先把 b, a + b 的值分别准备好,再依次交给原有的 a, b。

这样写的是傻逼

for x in range(3) 你知道是运行 3 次,那 for x in range(0) 是运行 1 次?是你犯糊了还是我犯糊了。

回到顶部