Python 3 索引错误

Posted

技术标签:

【中文标题】Python 3 索引错误【英文标题】:Python 3 Index Error 【发布时间】:2017-02-23 10:43:20 【问题描述】:

考虑以下代码:

def anadist(string1, string2):
    string1_list = []
    string2_list = []

    for i in range(len(string1)):
        string1_list.append(string1[i])
    for i in range(len(string2)):
        string2_list.append(string2[i])

    # Test returns for checking
    # return (string1_list,string2_list)
    # return len(string1_list)
    # return len(string2_list)

    for i in range(0,len(string1_list)):
        try:
            if (string1_list[i]) in string2_list:
                com = string1_list.pop(i)
                com_index = string2_list.index(com)
                string2_list.pop(com_index)
            else:
                pass
        except ValueError:
            pass
    return string1_list


def main():
    str1 = input("Enter string #1 >>> ")
    str2 = input("Enter string #2 >>> ")
    result = anadist(str1, str2)
    print(result)

#Boilerplate Check
if __name__ == "__main__":
    main()

在 Python 3.5.2 中运行会引发 IndexError:

Traceback (most recent call last):
  File "E:\CSE107L\Practice\anadist.py", line 34, in <module>
    main()
  File "E:\CSE107L\Practice\anadist.py", line 29, in main
    result = anadist(str1, str2)
  File "E:\CSE107L\Practice\anadist.py", line 15, in anadist
    if (string1_list[i]) in string2_list:
IndexError: list index out of range

而且我找不到问题所在。我写了另一个类似的代码并且有效:

def main():
    lst = [1,2,3,4,5]
    lst2 = [5,6,7,8,9]
    for i in range(len(lst)):
        if lst[i] in lst2:
            com = lst.pop(i)
            lst2_index = lst2.index(com)
            lst2.pop(lst2_index)
        else:
            pass
    print(lst)

if __name__ == "__main__":
    main()

我觉得错误来自我形成string1_list 的方式。这段代码用于计算形成一对单词的字谜需要多少个步骤。

【问题讨论】:

迭代列表时不能删除列表中的元素。在您的代码中,列表为 string1_list 【参考方案1】:

在某些情况下,您在迭代 string_list1 时会缩短它:

if (string1_list[i]) in string2_list:
    com = string1_list.pop(i)  # string1_list gets shorter here

但是,您的 range 不会改变。它仍然会从0 开始直到它计数到string1_list(不包括)的原始 长度。这将在任何时候调用string1_list.pop(i) 时导致IndexError

一种可能的解决方案是改用while 循环:

i = 0
while i < len(string1_list):
    try:
        if string1_list[i] in string2_list:
            com = string1_list.pop(i)
            com_index = string2_list.index(com)
            string2_list.pop(com_index)
        else:
            pass
    except ValueError:
        pass
    i += 1

这将导致在每次迭代后检查循环终止条件。如果您从string1_list 中删除一些元素,它仍然可以,因为循环将在i 变得足够大以超出其容器的边界之前终止。

【讨论】:

【参考方案2】:

您的问题是您正在通过执行string1_list.pop(i)for 循环内改变string1_list。通过执行string1_list.pop(i)for 循环内的列表长度正在减少,但您仍在对原始列表的长度进行迭代。

您的第二批代码之所以有效,是因为您在循环的最后一次迭代中只使用了pop

【讨论】:

【参考方案3】:

您的第二次尝试之所以有效,是因为仅在最后一个元素 5 中找到“匹配”,因此当您更改列表 lst 时,它是在 最后一次迭代期间并且没有效果。

您第一次尝试的问题是您可能会从列表的开头删除。计数器不会更新,并且在某些时候可能会达到列表中不再存在的值(它已被弹出)。尝试在输入中没有匹配项的情况下运行它,看看它是否有效。

一般来说,在迭代列表时不要改变列表。而不是:

for i in range(len(lst)):
    # mutate list

'idiom',你应该选择:

for i in list(list_object):   # or for i in list_object[:]:

它首先制作一个副本,并允许您通过保持变异和循环分开来变异原始 list_object

【讨论】:

以上是关于Python 3 索引错误的主要内容,如果未能解决你的问题,请参考以下文章

Python 3.x - iloc 抛出错误 - “单个位置索引器超出范围”

IndexError:列表索引超出范围 - python 错误

Python for 循环:“列表索引超出范围”错误?

Python - 索引错误 - 列表索引超出范围

Python 3.6“IndexError:列表索引超出范围”

Python中的数组索引