Почему существует необходимость явного удаления трассировки sys.exc_info ()? - PullRequest
12 голосов
/ 01 ноября 2009

Я видел в разных базах кода и только что прочитал на PyMOTW (см. Первое примечание здесь ).

В объяснении говорится, что цикл будет создан в случае, если обратный вызов назначен переменной из sys.exc_info()[2], но почему это так?

Насколько велика проблема? Должен ли я искать все варианты использования exc_info в моей базе кода и убедиться, что трассировка удалена?

Ответы [ 2 ]

20 голосов
/ 02 ноября 2009

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, которая указывает на сам стековый фрейм, создающий цикл, как те, что я показал выше.

11 голосов
/ 02 ноября 2009

Трассировка содержит ссылки на все активные фреймы, которые, в свою очередь, содержат ссылки на все локальные переменные в этих различных фреймах - эти ссылки являются большой частью самой работы объектов трассировки и фреймов, так что это неудивительно. Таким образом, если вы добавляете ссылку обратно в трассировку (или не можете быстро удалить ее, временно добавив ее), вы неизбежно формируете большой цикл ссылок - который мешает сбору мусора (и может остановить его вообще, если какой-либо из объектов в цикле принадлежат классы, которые переопределяют __del__, метод финализатора).

Особенно в долго работающей программе вмешательство в сборку мусора не лучшая идея, потому что вы будете держаться за память, которая вам не нужна (дольше, чем необходимо, или неопределенно долго, если вы по существу заблокировал сборку мусора в таких циклах, включив в них объекты с финализаторами.)

Итак, определенно лучше избавиться от следов как можно скорее, независимо от того, пришли они из exc_info или нет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...