斐波那契数列从0和1开始,后续每一项都是前两项之和。题目里的打印100以内,指的是只输出数值不超过100的所有项,而不是输出前100个项。这个边界条件如果处理不当,代码要么漏掉第一项,要么把超过100的144也打印出来。先看最简单的递推写法:用两个变量保存当前项和前一项,每次判断当前项是否小于等于100,再决定是否继续。

一、用递推变量构建基础循环
斐波那契数列的递推关系很直接:当前项等于前两项之和。程序里不需要保存整个列表,只需要维护两个变量 a 和 b,分别表示当前项和下一项。初始时 a 为0,b 为1。循环只要判断当前项 a 是否满足 a <= 100,满足就打印,然后更新 a 和 b。
a, b = 0, 1
while a <= 100:
print(a)
a, b = b, a + b上面这段代码的输出结果是:0、1、1、2、3、5、8、13、21、34、55、89。可以看到,89之后下一项是144,因为144大于100,循环条件不成立,所以不会打印144。这里的边界判断是数值边界,而不是项数边界。
代码中的 a, b = b, a + b 是Python的元组解包写法。右侧会先使用旧的 a 和 b 计算出一个元组,然后同时赋值给左侧。也就是说,a 得到旧的 b,b 得到旧的 a + b。这样做不需要额外的临时变量,代码更简洁,也不容易因为赋值顺序出错。
二、while循环实现中的常见错误
初学时很容易把更新和打印的顺序写反。例如下面这种写法虽然也能生成递推序列,但会输出越界值144:
a, b = 0, 1
while a <= 100:
a, b = b, a + b
print(a)这段代码的问题在于,当 a 为89、b 为144时,循环条件 89 <= 100 仍然成立,程序进入循环体,先执行更新把 a 变成144,然后打印144。直到下一次判断 144 <= 100 不成立时才退出。因此输出序列会多出一个超过100的项。
正确做法是先打印当前项,再更新变量。打印和判断都应当基于当前项 a,而更新动作放在循环体的最后。只要保持这个顺序,while 循环就能准确地在144出现之前停止。
如果不想直接使用元组解包,也可以写成临时变量形式。先计算下一项,再更新:
a, b = 0, 1
while a <= 100:
print(a)
next_value = a + b
a = b
b = next_value这种写法更接近其他编程语言的习惯,可读性也不错。但相比 a, b = b, a + b,多了一个 next_value 变量。实际开发中两者都可以,关键是保证当前项先被打印和判断。
三、递归与缓存的实现方式
斐波那契数列也可以通过递归定义实现。递归函数 fib(n) 返回第 n 项,基础情况是 n == 0 时返回0,n == 1 时返回1,其余情况返回前两项之和。如果要用递归打印100以内的数列,需要先确定最大项索引,然后逐个调用递归函数:
def fib(n):
if n == 0:
return 0
if n == 1:
return 1
return fib(n - 1) + fib(n - 2)
i = 0
while fib(i) <= 100:
print(fib(i))
i += 1这段代码虽然在逻辑上正确,但效率很低。每次调用 fib(i) 都会重新展开一棵递归树,已经计算过的值不会复用。随着 i 增大,重复计算次数呈指数级增长。对于100以内这个需求,最大项索引只有11左右,因此运行速度还能接受,但扩展到大数就会明显变慢。
可以引入 functools.lru_cache 来缓存已经计算过的递归结果,避免重复递归调用:
from functools import lru_cache
@lru_cache(maxsize=None)
def fib(n):
if n < 2:
return n
return fib(n - 1) + fib(n - 2)
i = 0
while fib(i) <= 100:
print(fib(i))
i += 1加上缓存后,每个 n 对应的斐波那契数只计算一次,之后直接从缓存读取。递归写法更贴近数学定义,适合用来理解递归思想。但就打印连续数列来说,它仍然不如递推循环简洁。实际工程中如果只需要序列,不推荐递归;如果要多次随机取某一项,缓存递归会更方便。
四、生成器方案与惰性求值
生成器是Python处理无限序列的常用方式。可以定义一个生成器函数,在无限循环中不断 yield 当前项,每次调用时只计算下一步,不会一次性生成所有项。打印100以内数列时可以借助 for 循环,当数值超过100时手动 break。
def fib_series():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
for num in fib_series():
if num > 100:
break
print(num)生成器的优势在于惰性求值。代码不会提前算出144或其他超过100的项,而是每次迭代时用一次 next 调用得到一个新值。for 循环在发现 num > 100 后执行 break,生成器会在 yield 语句处暂停,后续不再继续计算后面的项。这样既节省内存,又使逻辑边界清晰。
如果想直接得到列表,而不是逐行打印,可以使用 itertools.takewhile。它会从可迭代对象中一直取元素,直到条件不满足为止:
from itertools import takewhile
def fib_series():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
result = list(takewhile(lambda x: x <= 100, fib_series()))
print(result)整个表达式会返回 [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]。相比手动 break,takewhile 更适合函数式风格,也能直接得到列表结果。需要注意 fib_series 本身是一个无限生成器,如果没有 takewhile 或 break,直接对无限生成器调用 list 会导致程序一直运行下去。
五、输出格式与容易混淆的概念
默认情况下,print 每次调用都会自动换行,因此打印出来的每一项占一行。如果希望所有数列显示在同一行,可以给 print 传入 end=' ',用空格代替换行符:
def fib_series():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
for num in fib_series():
if num > 100:
break
print(num, end=' ')
print()这样输出结果就是 0 1 1 2 3 5 8 13 21 34 55 89。最后一个 print() 用来输出一个换行,防止后续提示符紧贴在数字后面。还可以把 end 改成其他分隔符,例如逗号加空格,但要注意末尾可能会多一个分隔符。
另一个容易混淆的地方是“100以内”和“前100个”的区别。100以内表示数值不超过100,数列长度由数值边界决定;前100个表示数量固定为100项,数值会很快超过100。打印前100项的代码控制的是项数,而不是数值大小:
a, b = 0, 1
for _ in range(100):
print(a)
a, b = b, a + b这段代码会输出前100个斐波那契数,其中第100项已经是非常大的整数。实际使用时务必根据需求判断是控制数值上限还是控制项数。理解了这一点,再把 while 判断条件换成任意数值,比如200或1000,就能灵活打印不同范围内的斐波那契数列。