В разделе разобраны функции модуля sys
, которые предоставляют информацию о трассировке и профилировании Python кода.
sys.gettrace()
- информация о функции трассировки,sys.settrace()
- устанавливает функцию трассировки,sys.call_tracing()
- вызывает функцию трассировки,sys.tracebacklimit
- количество уровней информации трассировки,sys.setprofile()
- устанавливает системную профилирования кода,sys.setdlopenflags()
- флаги при загрузке модулей расширения,sys.gettrace()
:Функция sys.gettrace()
предоставляет информацию о функции трассировки, которая была установлена при помощи функции sys.settrace()
.
sys.settrace(tracefunc)
:Функция sys.settrace()
устанавливает функцию трассировки системы tracefunc
, которая позволяет реализовать отладчик исходного кода Python на Python.
Функция tracefunc
зависит от потока. Чтобы отладчик поддерживал несколько потоков, он должен зарегистрировать функцию трассировки, используемую sys.settrace()
для каждого отлаживаемого или используемого потока threading.settrace()
.
Функции трассировки должны иметь три аргумента: frame
, event
и arg
. Аргумент frame
это текущий кадр стека. Событие event
является строка: 'call'
, 'line'
, 'return'
, 'exception'
или 'opcode'
. Аргумент arg
зависит от типа события.
Функция трассировки вызывается при установленном событии 'call'
всякий раз, когда вводится новая локальная область. Она должна возвращать ссылку на локальную функцию трассировки, которая будет использоваться для новой области или None
если область не должна отслеживаться.
Функция локальной трассировки должна возвращать ссылку на себя или на другую функцию для дальнейшей трассировки в этой области или None
отключает трассировку в этой области.
Если в функции трассировки произошла какая-либо, ошибка она будет сброшена, как это происходит для вызова sys.settrace(None)
.
События имеют следующее значение:
'call'
- вызвана функция или введен какой-то другой блок кода. Глобальная функция трассировки вызывается, arg
устанавливается в None
, возвращаемое значение указывает локальную функцию трассировки.'line'
- интерпретатор собирается выполнить новую строку кода или повторно выполнить условие цикла. Вызвана локальная функция трассировки, arg
устанавливается в None
, возвращаемое значение указывает новую локальную функцию трассировки. Отдельные события могут быть отключены для кадра, если f_trace_lines
установлено значение False
для этого кадра.'return'
- функция или другой блок кода собираются возвращать результат. Вызвана локальная функция трассировки. arg
- это значение, которое будет возвращено или будет None
если событие вызвано исключением. Возвращаемое значение функции трассировки игнорируется.'exception'
- произошло исключение. Вызвана локальная функция трассировки, arg
- это кортеж (exception, value, traceback)
, возвращаемое значение указывает новую локальную функцию трассировки.'opcode'
- интерпретатор собирается выполнить новый код операции. Вызвана локальная функция трассировки, arg
устанавливается в None
, возвращаемое значение указывает новую локальную функцию трассировки. События Per-opcode
не выдаются по умолчанию: они должны быть явно запрошены, установив на кадре f_trace_opcodes
в True
.Обратите внимание, на то как исключение распространяется по цепочке вызывающих сторон, событие 'exception'
генерируется на каждом уровне.
Для более детального использования можно установить функцию трассировки, явно назначив frame.f_trace=tracefunc
, вместо того, чтобы полагаться на ее косвенную установку через возвращаемое значение из уже установленной функции трассировки. Это также необходимо для активации функции трассировки в текущем кадре, чего не делает sys.settrace()
.
Обратите внимание: для того, чтобы это работало, должна быть установлена глобальная функция трассировки с sys.settrace()
, чтобы включить механизм трассировки во время выполнения. Но это не обязательно должна быть та же самая функция трассировки, например это может быть функция с низкими накладными расходами, которая просто возвращает None
, чтобы отключать себя на каждом кадре.
Вызывает событие аудита sys.settrace
без аргументов.
sys.call_tracing(func, args)
:Функция sys.call_tracing()
вызывает func(*args), пока включена трассировка. Состояние трассировки сохраняется, а затем восстанавливается. Функция sys.call_tracing()
предназначена для вызова отладчика из контрольной точки, чтобы рекурсивно отлаживать какой-то другой код.
sys.tracebacklimit
:Когда для переменной sys.tracebacklimit
задано целочисленное значение, оно определяет максимальное количество уровней информации трассировки, выводимой при возникновении необработанного исключения. По умолчанию это 1000
. Если установлено значение 0
или меньше, вся информация о трассировке подавляется и печатаются только тип и значение исключения.
sys.setprofile(profilefunc)
:Функция sys.setprofile()
устанавливает функцию profilefunc
, которая позволяет реализовать профилирование исходного кода Python в Python.
Функция профилирования вызывается аналогично функции трассировки (смотрите функцию sys.settrace()
), но вызывается с разными событиями, например, она не вызывается для каждой выполненной строки кода, а вызывается только при вызове и возврате результата, но при возврате результата сообщается событие, даже если было установлено исключение.
Функция sys.setprofile()
зависит от потока, но профилировщик не может знать о переключениях контекста между потоками, поэтому нет смысла использовать ее при наличии нескольких потоков. Кроме того, его возвращаемое значение не используется, поэтому она может просто вернуть None
. Ошибка в функции профиля приведет к отключению самой себя.
Функции профилирования должны иметь три аргумента: frame
, event
, и arg. frame
- текущий кадр стека. Событие event
представляет собой строку: 'call'
, 'return'
, 'c_call'
, 'c_return'
или 'c_exception'
. Текущий кадр стека arg
зависит от типа события.
Вызывает событие аудита sys.setprofile
без аргументов.
События имеют следующий смысл:
'call'
- вызывается функция или вводится какой-либо другой кодовый блок. Вызывается функция профиля. arg
- это None
.'return'
- функция или другой кодовый блок вот-вот вернет результат. Вызывается функция профиля. arg
- это значение, которое будет возвращено или None
, если событие вызвано вызванным исключением.'c_call'
- функция C вот-вот будет вызвана. Это может быть функция расширения или встроенная функция. arg
- это функция-объект.'c_return'
- функция C вернула результат. arg
- это функция-объект.'c_exception'
- функция C вызвала исключение. arg
- это функция-объект.sys.setdlopenflags(n)
:Функция sys.setdlopenflags()
устанавливает флаги n
, используемые интерпретатором для вызовов Unix dlopen()
, например, когда интерпретатор загружает модули расширения. Помимо прочего, это позволит лениво разрешать символы при импорте модуля, если он вызывается как sys.setdlopenflags(0)
.
Чтобы совместно использовать символы между модулями расширения, вызовите sys.setdlopenflags(os.RTLD_GLOBAL)
.
Символические имена значений флагов:
os.RTLD_LAZY
, os.RTLD_NOW
, os.RTLD_GLOBAL
, os.RTLD_LOCAL
, os.RTLD_NODELETE
, os.RTLD_NOLOAD
, os.RTLD_DEEPBIND
.
Что означают эти флаги, смотрите на странице руководства Unix dlopen(3)
.
Доступность: Unix.
Событие call
генерируется перед каждым вызовом функции. Кадр, переданный в функцию обратного вызова, можно использовать для определения, какая функция вызывается и откуда. В этом примере игнорируются вызовы write()
, используемые print()
для записи в sys.stdout
.
# test_settracel.py import sys def trace_calls(frame, event, arg): if event != 'call': return co = frame.f_code func_name = co.co_name if func_name == 'write': # Игнорировать вызовы write() при печати return func_line_no = frame.f_lineno func_filename = co.co_filename if not func_filename.endswith('test_settracel.py'): # Игнорировать вызовы не в этом модуле return caller = frame.f_back caller_line_no = caller.f_lineno caller_filename = caller.f_code.co_filename print(f'- Call to {func_name}') print(f'- on line {func_line_no} of {func_filename}') print(f'- from line {caller_line_no} of {caller_filename}') return def b(): print('inside b()\n') def a(): print('inside a()\n') b() sys.settrace(trace_calls) a() # - Call to a # - on line 31 of test_settracel.py # - from line 36 of test_settracel.py # inside a() # - Call to b # - on line 28 of test_settracel.py # - from line 33 of test_settracel.py # inside b()
Еще один полезный способ использования ловушек - следить за тем, какие функции вызываются и каковы их возвращаемые значения. Для отслеживания возвращаемых значений, нужно следить за событием return
.
import sys def trace_calls_returns(frame, event, arg): co = frame.f_code func_name = co.co_name if func_name == 'write': # Игнорировать вызовы write() return line_no = frame.f_lineno filename = co.co_filename if not filename.endswith('sys_settrace_return.py'): # Игнорировать вызовы не в этом модуле return if event == 'call': print(f'- Call to {func_name} on line {line_no} of {filename}') return trace_calls_returns elif event == 'return': print(f'- {func_name} => {arg}') return def b(): print('inside b()') return 'response_from_b ' def a(): print('inside a()') val = b() return val * 2 sys.settrace(trace_calls_returns) a() # - Call to a on line 32 of sys_settrace_return.py # inside a() # - Call to b on line 27 of sys_settrace_return.py # inside b() # - b => response_from_b # - a => response_from_b response_from_b
Локальная функция трассировки используется для отслеживания возвращаемых событий, поэтому функция trace_calls_returns()
при вызове должна возвращать ссылку на себя, чтобы можно было отслеживать возвращаемое значение.