Как я могу узнать, какой индекс находится вне диапазона?
в случае IndexError, есть ли способ, чтобы сказать, какой объект на линии "вне диапазона"?
рассмотрим этот код:
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
to len(a)
и len(b)
соответственно, но я любопытно, есть ли другой способ сделать это с помощью IndexError
.
5 ответов
более надежным подходом было бы нажать на объект traceback, возвращаемый sys.exc_info()
, извлеките код, указанный именем файла и номером строки из фрейма, используйте ast.parse
чтобы разобрать строку, подкласс ast.NodeVisitor
найти все Subscript
узлы, unparse (с astunparse
) и eval узлы с глобальными и локальными переменными кадра, чтобы увидеть, какой из узлов вызывает исключение, и распечатать оскорбительное выражение:
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
есть способ, но я бы не счел его очень надежным. Существует тонкая разница в сообщениях об ошибках:
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
обратите внимание на "назначение" в сообщении.
Итак, вы можете сделать что-то вроде:
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
опять же, я бы не доверял ему слишком много, он потерпит неудачу, если сообщение изменится в другой версии Питон.
на эти части исходного кода, эти разные сообщения действительно являются единственной разницей между двумя ошибками.
на IndexError
exception не хранит информацию о том, что вызвало исключение. Его единственными данными является сообщение об ошибке. Для этого вам нужно создать свой код.
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 = [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')