如何找出哪个指数超出范围?

Dav*_*ard 8 python exception index-error

如果出现IndexError,有没有办法判断一行上的哪个对象是"超出范围"?

考虑以下代码:

a = [1,2,3]
b = [1,2,3]

x, y = get_values_from_somewhere()

try:
   a[x] = b[y]
except IndexError as e:
   ....
Run Code Online (Sandbox Code Playgroud)

如果x或者y太大而IndexError被抓住,我想知道哪个a或哪个b超出范围(所以我可以在except块中执行不同的操作).

显然,我可以比较x,并ylen(a)len(b)分别,但我很好奇,如果有使用这样做的另一种方式IndexError.

Thi*_*lle 8

有一种方法,但我不认为它非常强大.错误消息有细微差别:

a = [1,2,3]
b = [1,2,3]

a[2] = b[3]

---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-69-8e0d280b609d> in <module>()
      2 b = [1,2,3]
      3 
----> 4 a[2] = b[3]

IndexError: list index out of range
Run Code Online (Sandbox Code Playgroud)

但如果错误在左侧:

a[3] = b[2]

---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-68-9d66e07bc70d> in <module>()
      2 b = [1,2,3]
      3 
----> 4 a[3] = b[2]

IndexError: list assignment index out of range
Run Code Online (Sandbox Code Playgroud)

请注意消息中的"赋值".

所以,你可以这样做:

a = [1,2,3]
b = [1,2,3]

try:
    a[3] = b[2]
except IndexError as e:
    message = e.args[0]
    if 'assignment' in message:
        print("Error on left hand side")
    else:
        print("Error on right hand side")
Run Code Online (Sandbox Code Playgroud)

输出:

# Error on left hand side
Run Code Online (Sandbox Code Playgroud)

同样,我不会太信任它,如果消息在另一个版本的Python中发生变化,它将失败.


我看了一下源代码的这些部分,这些不同的消息确实是两个错误之间唯一的区别.


Oli*_*çon 5

IndexError异常不存储有关引发异常的信息.它唯一的数据是错误信息.你必须制作你的代码才能这样做.

a = [1,2,3]
b = [1,2,3]

x, y = get_values_from_somewhere()

try:
    value = b[y]
except IndexError as e:
   ...

try:
    a[x] = value
except IndexError as e:
    ...
Run Code Online (Sandbox Code Playgroud)

我想补充一下,我试图恢复罪魁祸首inspect.frame,但无法这样做.因此,我怀疑确实没有强大的方法.

最后,请注意,这是特定的,IndexError因为其他异常可能包含推断导致它们的原因所需的信息.例如,a KeyError包含引发它的键.


blh*_*ing 5

更可靠的方法是利用 所返回的回溯对象sys.exc_info(),从帧中提取由文件名和行号指示的代码,用于ast.parse解析该行,子类化ast.NodeVisitor以查找所有Subscript节点,解解析(使用astunparse)并评估具有框架的全局和局部变量的节点,以查看哪个节点导致异常,并打印有问题的表达式:

import sys
import linecache
import ast
import astunparse

def find_index_error():
    tb = sys.exc_info()[2]
    frame = tb.tb_frame
    lineno = tb.tb_lineno
    filename = frame.f_code.co_filename
    line = linecache.getline(filename, lineno, frame.f_globals)
    class find_index_error_node(ast.NodeVisitor):
        def visit_Subscript(self, node):
            expr = astunparse.unparse(node).strip()
            try:
                eval(expr, frame.f_globals, frame.f_locals)
            except IndexError:
                print("%s causes IndexError" % expr)
    find_index_error_node().visit(ast.parse(line.strip(), filename))

a = [1,2,3]
b = [1,2,3]
x, y = 1, 2
def f():
    return 3
try:
    a[f() - 1] = b[f() + y] + a[x + 1] # can you guess which of them causes IndexError?
except IndexError:
    find_index_error()
Run Code Online (Sandbox Code Playgroud)

这输出:

b[(f() + y)] causes IndexError
Run Code Online (Sandbox Code Playgroud)