列表索引超出范围错误
大家好,我是个初学者。我写了一个程序,可以把文件输出为.txt格式,然后又用另一个程序来读取这些文件并使用它们。我用一个列表来存储这些值(len(..)给我返回的结果是100,表示所有文件都有100个值)。但是,每当我运行这个代码:
for w in range(1,20): # i want files file01-file20 excluding file00
for x in range(100):
c=c+1 #counter to keep list position on f=0
exec "f=open('file%02d.txt','r').readlines()"%w #stores data from file00,file01,file02...
f00=open('file00.txt','r').readlines() #same as ^ but from file00
for y in range(100):
xvp=float(f[c].rstrip('\n')) #the error is on this line; the file are stored in vertical order
pvp=float(f00[y].rstrip('\n')) #maybe even this one
#and i do stuff with those values...
我在第12行遇到了问题,
xvp=float(f[c].rstrip('\n'))
出现了错误:IndexError: list index out of range(索引超出范围)
注意:在这些.txt文件中,每一行都有100个数字。
如果你们有什么办法可以帮助我,请告诉我。谢谢!
3 个回答
有100个数字存储在.txt文件的不同的行里。
但是在
for w in range(1,20): # i want files file01-file20 excluding file00
for x in range(100):
c=c+1 #counter to keep list position on f=0
你把c增加了20*100 = 2000次。
也许你需要在“w”循环中把c设为0,或者干脆用x代替c?
根据你描述的文件情况,你在访问它们时出现了错误。你使用的 c
是在第二个循环中每次增加的,这样它的值会达到2000。用 x
似乎是更合理的选择。
#restructured for efficiency
file = open('file00.txt','r')
f00 = file.readlines() #no need to reopen the file for every iteration
file.close() #always close the file when done with
for w in range(1,20):
file = open('file%02d.txt'%w,'r')
f = file.readlines() #only open once per iteration
file.close()
for x in range(100):
xvp = float(f[x].rstrip('\n'))
for y in range(100):
pvp = float(f00[y].rstrip('\n'))
#do stuff
你似乎在把 c
增加了两千次(20乘以100,实际上只增加了1900次,因为 range(1,20)
不会达到20,这点你在评论中提到过)——所以如果用它来索引一个有100个元素的列表,自然会超出范围!整个代码看起来有点乱,我建议你彻底重构一下,避免使用 exec
,按照Python的方式来做。假设你使用的是Python 2.6或更高版本(在2.5中,你需要在模块开头加上 from __future__ import with_statement
):
f00 = open('file00.txt').readlines()
for w in range(1, 21):
for x in range(100):
with open('file%02d.txt' % w) as f:
for line in f:
xvp = float(line)
for line00 in f00:
rvp = float(line00)
do_stuff(xvp, rvp)
我不知道这是否是你想要的逻辑——把 file00.txt
的每一行和另外20个文件的每一行都配对——但至少这样可以让你清楚每一行是如何配对的;-)。如果你想要的是只把 file00.txt
的第一行和其他每个文件的第一行配对,第二行和第二行配对,依此类推,那么在模块开头加上 import itertools
,并把 with
的内容改成:
for line00, line in itertools.izip(f00, f):
rvp = float(line00)
xvp = float(line)
do_stuff(xvp, rvp)
等等。
注意,我是把 file00.txt
的所有内容一次性读入内存(放到 f00
这个行列表中),因为你显然需要多次循环这些内容,但其他文件就不需要这样做。
一个明显的优化是,只把 file00.txt
的行转换为浮点数一次,替换掉 f00 =
这行代码为:
with open('file00.txt') as f:
rvps = [float(line) for line in f]
然后直接使用 rvps
,而不是每次都对 f00
中的字符串进行转换——例如,在第二个版本(使用 itertools.izip
的那个):
for rvp, line in itertools.izip(rvps, f):
xvp = float(line)
do_stuff(xvp, rvp)
编辑:我发现自己在不知不觉中做了一些小改进,也许我应该更详细地解释一下;-)。打开文件进行读取时,不需要传递 'r'
(虽然这样做没有坏处,但通常习惯上可以省略)。在调用 float
之前,不需要去掉字符串前后的空白——float
会自动跳过这些空白。我还修复了一个明显的错误(你不会处理 file20.txt
),通过把适用的 range
改为 range(1, 21)
。
with open(...) as f:
语句负责打开文件,把名字 f
绑定到打开的文件对象上,并且一旦控制的语句块执行完,就保证文件会被正确关闭——这几乎总是比单独使用 open
更好,因为确保所有文件尽快关闭是非常好的习惯(with
语句还有很多其他优秀的用法,但这是最常见的一个,也是实现这个功能所必需的)。
直接在打开的文件对象 f
上循环(只要文件是以文本模式打开的,这里默认都是这样),for line in f:
会逐行提供 f
的内容(而不需要一次性把所有内容都放在内存中),这是一个非常流行且好的Python习惯。
构造 rvps = [float(line) for line in f]
,我在推荐的优化中使用的这个,被称为“列表推导式”,它是一个快速且简洁的替代方案,用于构建一个新的列表。
itertools.izip
,给定多个可迭代对象,提供一个单一的可迭代对象,其项是由其他可迭代对象的项“同步”组成的元组。内置的 zip
也类似,但(在Python 2中)它会在内存中构建一个列表,而 itertools.izip
则避免了这种情况,因此学习使用 itertools
版本是个好习惯,以避免浪费内存(对于像你这样的小文件来说并不太重要,但养成好习惯总是最好的,应该“自然而然”地去做,而不是每次都要思考——就像人们早上起床时不会思考是否要刷牙,而是自然而然地去做一样;-)。
我相信还有更多,但这些是我想到的。如果你需要进一步的帮助,请随时问我!