列表索引超出范围错误

0 投票
3 回答
931 浏览
提问于 2025-04-16 02:50

大家好,我是个初学者。我写了一个程序,可以把文件输出为.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 个回答

1

有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?

1

根据你描述的文件情况,你在访问它们时出现了错误。你使用的 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
4

你似乎在把 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 版本是个好习惯,以避免浪费内存(对于像你这样的小文件来说并不太重要,但养成好习惯总是最好的,应该“自然而然”地去做,而不是每次都要思考——就像人们早上起床时不会思考是否要刷牙,而是自然而然地去做一样;-)。

我相信还有更多,但这些是我想到的。如果你需要进一步的帮助,请随时问我!

撰写回答