Python 如果 vs. 循环?
我有一个读取小文件的程序,我只想要前200条记录。这个程序可以正常工作,但在这个过程中,我搞不清楚为什么使用“while”这个结构会出问题。
这段代码可以正常运行:
import csv, sys, zipfile
sys.argv[0] = "/home/tom/Documents/REdata/AllListing1RES.zip"
zip_file = zipfile.ZipFile(sys.argv[0])
items_file = zip_file.open('AllListing1RES.txt', 'rU')
rows = []
for row_index, row in enumerate(csv.DictReader(items_file, dialect='excel', delimiter='\t')):
if (row_index < 200):
rows.append(row)
else : break
而这段代码会一直运行,直到出现内存不足的错误。我本以为这两段代码是一样的?
import csv, sys, zipfile
sys.argv[0] = "/home/tom/Documents/REdata/AllListing1RES.zip"
zip_file = zipfile.ZipFile(sys.argv[0])
items_file = zip_file.open('AllListing1RES.txt', 'rU')
rows = []
for row_index, row in enumerate(csv.DictReader(items_file, dialect='excel', delimiter='\t')):
while (row_index < 200):
rows.append(row)
else : break
那么,使用“while”时,正确的写法应该是什么呢?
5 个回答
0
这两个代码不能等价,因为在你第一个代码里,只有一个循环在运行(就是那个 for 循环),它会在每次 row_index 的变化时检查 if-else 语句。而在你第二个代码里,while 循环是一个嵌套循环,但它的条件没有被满足(因为没有东西在改变 row_index)。这样就会导致它一直循环下去,最终出现内存错误。
6
这两个东西不一样,因为在你的 while 循环里,有个条件是 row_index < 200
,这个条件永远不会变成假,因为在这个循环里,row_index
的值不会改变。
这就是你遇到内存问题的原因,因为你可能陷入了一个无限循环。
你实际上是在说:
伪代码:
stay in block one as long as row_index < 200:
block_one:
rows.append(row)
goto block_one
你可以看到 row_index
永远不会改变,所以你会一直停留在 block_one 里。
而 if 语句的伪代码是:
if row_index < 200 goto block_one otherwise break:
block_one:
rows.append(row)
你可以看到 block_one
不会像在 while 循环中那样回到自己。
3
写这个循环的传统方式是这样的:
for row_index, row in enumerate(csv.DictReader(items_file, dialect='excel', delimiter='\t')):
if (row_index >= 200):
break
rows.append(row)
当行计数器达到200时,我们就会退出这个循环。
如果想用 while
循环来代替 for
循环(注意,while
循环是 for
的一种替代方式,而不是 if
的替代方式),那么就需要手动控制迭代器:
itr = enumerate(csv.DictReader(items_file, dialect='excel', delimiter='\t'))
row_index = -1
while row_index < 199:
try:
row_index, row = next(itr) # Python 3. Use itr.next() in Python 2
except StopIteration:
break # Ran out of data
rows.append(row)
说到这里,其实在 itertools
模块中还有一个更好的选择,可以用来替代这两种方式:
from itertools import islice
itr = csv.DictReader(items_file, dialect='excel', delimiter='\t')
rows = list(islice(itr, 200))