请实现一个函数,其功能为检查List中是否含有数字6。代码很简单,可能有人会这样写:
def check(arr):
for i in range(len(arr)):
if arr[i] == 6:
appear = True
break
if i == len(arr): appear = False
print("6 appears in arr? ", appear)
上述代码很简单,如果找到6,appear
赋值为True
,结束循环;如果找不到,那么i
会增加至len(arr)
,从而判断不含有6.
下面我们测试一下:
check([1,2,3,4,5,6,7])
# 运行结果: 6 appears in arr? True
check([1,2,3,4])
# 运行结果:UnboundLocalError: local variable 'appear' referenced before assignment
什么鬼,竟然说appear
在赋值前使用。这很不科学,因为从上面的代码看,如果找到appear
会赋值为True
,找不到会赋值为False
,怎么会没有赋值呢?
原因是我们想当然的觉得找不到,i
会增加至len(arr)
。其实并不是这样的,如下面的代码所示:
for i in range(5):
print(i)
print("after loop i == ", i)
# 运行结果:
0
1
2
3
4
after loop i == 4
这下真相大白了,i
并不会想我们设想的那样变成5
,而是4
.
我们之所以会有错误的设想,其实是受“传统”for循环的影响,以C++代码为例:
int i;
for (i = 0; i < 5; ++i)
cout << i << endl;
cout << "after loop i == " << i << endl;
// 运行结果
0
1
2
3
4
after loop i == 5
造成这种差异的是二者实现上的差异,range
实际上返回了一个迭代器,迭代器依次返回0, 1, 2, 3, 4
,i
不可能变成5
;而C++则是通过i < 5
来控制语句结束的,当i==5
时,for循环结束。
同样是for语句,却因为实现的不同存在这样细微的差异。所以说,一定要注意语言之间的差异,不能想当然的用一种语言写另外一种语言风格的代码,不然很容易出现极其隐蔽的bug。