Автор оригинала: Doug Hellmann.
Есть два способа ввести код для наблюдения за выполнением программы: трассировка и профилирование . Они похожи, но предназначены для разных целей и поэтому имеют разные ограничения. Самый простой, но наименее эффективный способ контролировать программу – использовать обработчик трассировки , который можно использовать для написания отладчика, отслеживания покрытия кода или достижения многих других целей.
Ловушка трассировки изменяется путем передачи функции обратного вызова в sys.settrace ()
. Обратный вызов получит три аргумента: кадр стека из выполняемого кода, строку с указанием типа уведомления и значение аргумента для конкретного события. в таблице ниже перечислены семь типов событий для различных уровней информации, возникающих при выполнении программы.
Перехватчики событий для settrace ()
Мероприятие
Когда это происходит
Значение аргумента
вызов
Перед выполнением строки
Никто
линия
Перед выполнением строки
Никто
возвращаться
Прежде чем функция вернется
Возвращаемое значение
исключение
После возникновения исключения
Кортеж (исключение, значение, трассировка)
c_call
Перед вызовом функции C
Объект функции C
c_return
После возврата функции C
Никто
c_exception
После того, как функция C выдает ошибку
Никто
Вызов функций отслеживания
Событие call
генерируется перед каждым вызовом функции. Кадр, переданный в обратный вызов, можно использовать, чтобы узнать, какая функция вызывается и откуда.
sys_settrace_call.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
#!/usr/bin/env python3 # encoding: utf-8 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': # Ignore write() calls from printing return func_line_no frame.f_lineno func_filename co.co_filename if not func_filename.endswith('sys_settrace_call.py'): # Ignore calls not in this module return caller frame.f_back caller_line_no caller.f_lineno caller_filename caller.f_code.co_filename print('* Call to', func_name) print('* on line {} of {}'.format( func_line_no, func_filename)) print('* from line {} of {}'.format( caller_line_no, caller_filename)) return def b(): print('inside b()\n') def a(): print('inside a()\n') b() sys.settrace(trace_calls) a()
В этом примере игнорируются вызовы write ()
, которые используются print
для записи в sys.stdout
.
$ python3 sys_settrace_call.py * Call to a * on line 35 of sys_settrace_call.py * from line 41 of sys_settrace_call.py inside a() * Call to b * on line 31 of sys_settrace_call.py * from line 37 of sys_settrace_call.py inside b()
Трассировка внутренних функций
Ловушка трассировки может возвращать новую ловушку, которая будет использоваться внутри новой области (функция трассировки local ). Например, можно управлять трассировкой только построчно в определенных модулях или функциях.
sys_settrace_line.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
#!/usr/bin/env python3 # encoding: utf-8 import functools import sys def trace_lines(frame, event, arg): if event 'line': return co frame.f_code func_name co.co_name line_no frame.f_lineno print('* {} line {}'.format(func_name, line_no)) def trace_calls(frame, event, arg, to_be_traced): if event 'call': return co frame.f_code func_name co.co_name if func_name 'write': # Ignore write() calls from printing return line_no frame.f_lineno filename co.co_filename if not filename.endswith('sys_settrace_line.py'): # Ignore calls not in this module return print('* Call to {} on line {} of {}'.format( func_name, line_no, filename)) if func_name in to_be_traced: # Trace into this function return trace_lines return def c(input): print('input =', input) print('Leaving c()') def b(arg): val arg * 5 c(val) print('Leaving b()') def a(): b(2) print('Leaving a()') tracer functools.partial(trace_calls, to_be_traced['b']) sys.settrace(tracer) a()
В этом примере список функций хранится в переменной: py“to_be_traced“, поэтому при запуске trace_calls ()
он может вернуть trace_lines ()
для включения трассировки. внутри b ()
.
$ python3 sys_settrace_line.py * Call to a on line 49 of sys_settrace_line.py * Call to b on line 43 of sys_settrace_line.py * b line 44 * b line 45 * Call to c on line 38 of sys_settrace_line.py input = 10 Leaving c() * b line 46 Leaving b() Leaving a()
Наблюдая за стеком
Еще один полезный способ использования ловушек – следить за тем, какие функции вызываются и каковы их возвращаемые значения. Чтобы отслеживать возвращаемые значения, следите за событием return
.
sys_settrace_return.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
#!/usr/bin/env python3 # encoding: utf-8 import sys def trace_calls_and_returns(frame, event, arg): co frame.f_code func_name co.co_name if func_name 'write': # Ignore write() calls from printing return line_no frame.f_lineno filename co.co_filename if not filename.endswith('sys_settrace_return.py'): # Ignore calls not in this module return if event 'call': print('* Call to {} on line {} of {}'.format( func_name, line_no, filename)) return trace_calls_and_returns elif event 'return': print('* {} => {}'.format(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_and_returns) a()
Функция локальной трассировки используется для отслеживания возвращаемых событий, поэтому trace_calls_and_returns ()
должен возвращать ссылку на себя при вызове функции, поэтому возвращаемое значение можно отслеживать.
$ python3 sys_settrace_return.py * 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
Распространение исключений
Исключения можно отслеживать, ища событие exception
в локальной функции трассировки. Когда возникает исключение, ловушка трассировки вызывается с кортежем, содержащим тип исключения, объект исключения и объект трассировки.
sys_settrace_exception.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
#!/usr/bin/env python3 # encoding: utf-8 import sys def trace_exceptions(frame, event, arg): if event 'exception': return co frame.f_code func_name co.co_name line_no frame.f_lineno exc_type, exc_value, exc_traceback arg print(('* Tracing exception:\n' '* {} "{}"\n' '* on line {} of {}\n').format( exc_type.__name__, exc_value, line_no, func_name)) def trace_calls(frame, event, arg): if event 'call': return co frame.f_code func_name co.co_name if func_name in TRACE_INTO: return trace_exceptions def c(): raise RuntimeError('generating exception in c()') def b(): c() print('Leaving b()') def a(): b() print('Leaving a()') TRACE_INTO ['a', 'b', 'c'] sys.settrace(trace_calls) try: a() except Exception as e: print('Exception handler:', e)
Позаботьтесь о том, чтобы ограничить область применения локальной функции, поскольку некоторые внутренние элементы сообщений об ошибках форматирования генерируют и игнорируют свои собственные исключения. Перехватчик трассировки видит каждое исключение, независимо от того, перехватывает и игнорирует вызывающий объект.
$ python3 sys_settrace_exception.py * Tracing exception: * RuntimeError "generating exception in c()" * on line 31 of c * Tracing exception: * RuntimeError "generating exception in c()" * on line 35 of b * Tracing exception: * RuntimeError "generating exception in c()" * on line 40 of a Exception handler: generating exception in c()
Смотрите также
- profile – в документации модуля
profile
показано, как использовать готовый профилировщик. - trace – модуль
trace
реализует несколько функций анализа кода. - Типы и члены – описания объектов фрейма и кода и их атрибутов.
- Отслеживание кода Python – Другой
settrace ()
учебник. - Wicked hack: трассировка байт-кода Python – эксперименты Неда Батчелдера с трассировкой с большей детализацией, чем на уровне исходной строки.
- смайлик – Python Application Tracer