Почему при трассировке ошибок отображается отредактированный сценарий, а не тот, который фактически выполнялся? - PullRequest
3 голосов
/ 03 апреля 2019

Фон

Рассмотрим следующий минимальный пример:

Когда я сохраняю следующий скрипт и запускаю его из терминала,

import time

time.sleep(5)
raise Exception

код вызовет ошибку после того, какспит пять секунд, оставляя следующую трассировку.

трассировка (последний вызов был последним):
Файл "test / minimal_error.py", строка 4, в
повышение исключения
Исключение

Теперь, скажем, я запускаю скрипт, и во время 5-секундного сна я добавляю строку посередине.

import time

time.sleep(5)
a = 1
raise Exception

ПослеИнтерпретатор python выходит из спящего режима и достигает следующей строки, raise Exception, вызывает ошибку, но оставляет следующую трассировку.

Трассировка (последний вызов был последним):
Файл "test / minimal_error.py", строка 4, в
a = 1
Исключение

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

На практике я реализую одну часть программы, запускаю ее, чтобы посмотреть, хорошо ли работает эта часть, и, пока она еще работает, я перехожу к следующей вещи, которую мне нужно реализовать.И когда скрипт выдает ошибку, я должен найти, какая именно строка кода вызвала ошибку.Я обычно просто читаю сообщение об ошибке и пытаюсь определить исходный код, вызвавший его.Иногда это нелегко догадаться, поэтому я копирую скрипт в буфер обмена и откатываю код, отменив то, что я написал после запуска скрипта, проверил строку, вызвавшую ошибку, и вставил обратно из буфера обмена.

Вопрос

Есть ли понятная причина, почему интерпретатор показывает a = 1, что является строкой 4 «текущей» версии кода, вместо raise Exception, которая является строкой 4 «работающей»версия кода?Если интерпретатор знает, что «строка 4» вызвала ошибку, а сообщение об ошибке «Исключение», почему он не может сказать, что команда raise Exception подняла ее?

Я не совсем уверен, что этот вопроспо теме, но я не думаю, что смогу сделать вывод о том, что не по теме из того, что говорит справочный центр .Я думаю, что речь идет о «программном [инструменте], обычно используемом программистами» (интерпретатор Python), и является «практической, ответственной проблемой, уникальной для разработки программного обеспечения».Я не думаю, что это основано на мнении, потому что должна быть причина для такого выбора реализации.

(наблюдается то же самое в Python 2.7.16, 3.6.8, 3.7.2 и 3.7.3так что это не похоже на конкретную версию, но это просто происходит в Python.)

Ответы [ 2 ]

5 голосов
/ 03 апреля 2019

Непосредственной причиной является то, что Python повторно открывает файл и снова читает указанную строку, чтобы напечатать его в сообщениях об ошибках. Так зачем ему это делать, когда он уже прочитал файл в начале? Потому что он не сохраняет исходный код в памяти, а только сгенерированный байт-код.

Фактически, Python никогда не будет хранить все содержимое исходного файла в памяти за один раз. Вместо этого лексер будет читать из файла и выдавать один токен за раз, который затем анализатор анализирует и превращает в байт-код. Как только парсер завершит работу с токеном, он исчезнет.

Таким образом, единственный способ вернуться к исходному исходному коду - это снова открыть исходный файл.

0 голосов
/ 24 апреля 2019

Я думаю, что это классическая проблема, которая описана здесь .

Sleep использует системный вызов os, чтобы приостановить выполнение этого потока.

...