这几天我的一个程序出了一个不会报错的莫名其妙的bug。
我把这个问题以最简化的代码复现如下:
class AA():
def __init__(self):
super(AA, self).__init__()
def __getitem__(self, item):
a = [1, 2, 3]
b = a[999] # list索引越界
return b
aa = AA()
out = []
for b in aa:
out.append(b)
if len(out) >= 10:
break
print(out)
正常list索引越界问题解释器会报错的, 但是这段代码不报错,会打印一个空列表出来。每次for循环都会执行0次直接跳出循环,而且解释器不报出任何错误信息,如果程序较为复杂,寻找bug过程会相当艰辛。
其实这里是一个for循环运行机制导致的语法陷阱,所以要弄清楚这个问题的深层次原因我们要先弄清楚for循环的运行机制:【python中for循环的运行机制】
现在回到上边代码的bug问题,语法陷阱是这样产生的:
- for语句调用内置方法iter(aa)得到了一个临时迭代器
- 程序执行到
b = a[999] # list索引越界
这行的时候抛出了索引越界异常:IndexError - 临时迭代器捕获到这个异常后当作数据索引完毕的信号而并没有处理这个异常(这就是问题的关键),随后迭代器抛出异常:
StopIteration
- for语句捕获到
StopIteration
后结束了循环
整个过程没有一个报错,list索引越界异常被完美隐藏。
这个问题从出现到难以查找bug的原因是对python的内部运行原理不够深入了解,但我相信很多人和我一样把python当作开箱即用的编程语言,没有花很多时间去深入学习它,这也是python一个优点。