Python 3 (обновить до исходного ответа):
В Python 3 приведенный в вопросе совет был удален из документации по Python. Мой оригинальный ответ (который следует ниже) относится только к тем версиям Python, которые включают цитату в свою документацию.
Python 2:
Сборщик мусора Python, в конце концов, найдет и удалит циклические ссылки, подобные созданным, ссылаясь на стек трассировки внутри одного из стековых фреймов, поэтому не возвращайтесь и не переписывайте свой код. Но, двигаясь вперед, вы можете последовать совету
http://docs.python.org/library/sys.html
(где документ exc_info()
) и сказать:
exctype, value = sys.exc_info()[:2]
когда вам нужно получить исключение.
Еще две мысли:
Во-первых, почему вы вообще используете exc_info()
?
Если вы хотите поймать исключение, вы не должны просто сказать:
try:
...
except Exception as e: # or "Exception, e" in old Pythons
... do with with e ...
вместо того, чтобы копаться с объектами внутри модуля sys
?
Второе: хорошо, я дал много советов, но на самом деле не ответил на ваш вопрос. : -)
Почему создается цикл? Ну, в простых случаях цикл создается, когда объект ссылается на себя:
a = [1,2,3]
a.append(a)
Или когда два объекта ссылаются друг на друга:
a = [1,2,3]
b = [4,5,a]
a.append(b)
В обоих этих случаях, когда функция завершает работу, значения переменных все еще будут существовать, потому что они заблокированы в объёме подсчета ссылок: ни один не может уйти, пока другой не уйдет первым! Только современный Python сборщик мусора может решить эту проблему, в конечном итоге заметив цикл и разорвав его.
И поэтому ключом к пониманию этой ситуации является то, что объект «traceback» - третья вещь (в индексе № 2), возвращаемая exc_info()
- содержит «кадр стека» для каждой функции, которая была активной, когда исключение было называется. И эти стековые кадры являются , а не «мертвыми» объектами, показывающими, что было истиной, когда вызывалось исключение; кадры еще живы! Функция, которая перехватила исключение, все еще жива, поэтому ее стековый фрейм является живым существом, все еще растущим и теряющим ссылки на переменные, поскольку его код выполняется для обработки исключения (и делает все остальное, что он делает, когда завершает предложение «кроме» и выходит о своей работе).
Поэтому, когда вы говорите t = sys.exc_info()[2]
, один из этих стековых фреймов внутри трассировки - фактически, фрейм, принадлежащий той самой функции, которая выполняется в данный момент - теперь содержит переменную с именем t
, которая указывает на сам стековый фрейм, создающий цикл, как те, что я показал выше.