如何找出哪个索引超出范围?
How can I find out which index is out of range?
如果出现 IndexError,有没有办法判断一行中的哪个对象是 'out of range'?
考虑这段代码:
a = [1,2,3]
b = [1,2,3]
x, y = get_values_from_somewhere()
try:
a[x] = b[y]
except IndexError as e:
....
如果x
或y
太大而IndexError
被抓到,我想知道a
或b
中的哪一个超出范围(因此我可以在 except
块中执行不同的操作)。
显然我可以将 x
和 y
分别与 len(a)
和 len(b)
进行比较,但我很好奇是否还有另一种使用 IndexError
.
不,无法使用抛出的 IndexError 推断两者中的哪一个越界。
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:
...
我想补充一点,我试图通过 inspect.frame
恢复罪魁祸首,但未能成功。因此我怀疑真的没有可靠的方法。
最后,请注意这是特定于 IndexError
的,因为其他异常可能包含推断导致它们的原因所需的信息。例如,KeyError
包含引发它的密钥。
有一种方法,但我认为它不是很可靠。错误消息有细微差别:
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
但如果错误在左侧:
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
注意消息中的 'assignment'。
所以,你可以这样做:
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")
输出:
# Error on left hand side
同样,我不会太相信它,如果消息在 Python 的另一个版本中发生变化,它将失败。
我查看了 these parts of the source code,这些不同的消息确实是两个错误之间的唯一区别。
也许是这样的?
a = [1,2,3]
b = [2,3,4]
x = 5
y = 1
try:
a[x] = b[y]
except IndexError:
try:
a[x]
print('b caused indexerror')
except IndexError:
print('a caused indexerror')
更稳健的方法是利用sys.exc_info()
返回的回溯对象,从框架中提取文件名和行号指示的代码,使用ast.parse
解析该行, 子类 ast.NodeVisitor
以找到所有 Subscript
节点, unparse (with 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()
这输出:
b[(f() + y)] causes IndexError
如果出现 IndexError,有没有办法判断一行中的哪个对象是 'out of range'?
考虑这段代码:
a = [1,2,3]
b = [1,2,3]
x, y = get_values_from_somewhere()
try:
a[x] = b[y]
except IndexError as e:
....
如果x
或y
太大而IndexError
被抓到,我想知道a
或b
中的哪一个超出范围(因此我可以在 except
块中执行不同的操作)。
显然我可以将 x
和 y
分别与 len(a)
和 len(b)
进行比较,但我很好奇是否还有另一种使用 IndexError
.
不,无法使用抛出的 IndexError 推断两者中的哪一个越界。
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:
...
我想补充一点,我试图通过 inspect.frame
恢复罪魁祸首,但未能成功。因此我怀疑真的没有可靠的方法。
最后,请注意这是特定于 IndexError
的,因为其他异常可能包含推断导致它们的原因所需的信息。例如,KeyError
包含引发它的密钥。
有一种方法,但我认为它不是很可靠。错误消息有细微差别:
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
但如果错误在左侧:
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
注意消息中的 'assignment'。
所以,你可以这样做:
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")
输出:
# Error on left hand side
同样,我不会太相信它,如果消息在 Python 的另一个版本中发生变化,它将失败。
我查看了 these parts of the source code,这些不同的消息确实是两个错误之间的唯一区别。
也许是这样的?
a = [1,2,3]
b = [2,3,4]
x = 5
y = 1
try:
a[x] = b[y]
except IndexError:
try:
a[x]
print('b caused indexerror')
except IndexError:
print('a caused indexerror')
更稳健的方法是利用sys.exc_info()
返回的回溯对象,从框架中提取文件名和行号指示的代码,使用ast.parse
解析该行, 子类 ast.NodeVisitor
以找到所有 Subscript
节点, unparse (with 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()
这输出:
b[(f() + y)] causes IndexError