Автор оригинала: Robin Andrews.
Способность трассировка Значения переменных во время выполнения программы является отличной помощью в обеспечении вашего кода, что он должен делать, и избегая Логические ошибки – Эти надоенные ошибки, которые не разбивают вашу программу, но дают вам неожиданные результаты или даже скользят, что вы незамечены только, чтобы вернуться и укусить вас позже.
В некоторых компьютерных науках этот навык поступает под тему Корректирующее обслуживание Отказ Например, Кембриджская компьютерная наука Уровень имеет следующие цели, относящиеся к этой теме:
- Выполните тестирование белого ящика:
- Выбор подходящих данных
- используя таблицу трассировки
- Определите любые ошибки в алгоритме, используя завершенную таблицу трассировки
- Изменить алгоритм, если требуется
Один из способов отслеживать значения в качестве выполнения программы, используя Таблица следа Отказ Способность создавать их очень полезно в реальном развитии программных решений, а также часто тестируются в актуальных документах информационных наук. В то время как это, безусловно, стоит иметь возможность отслеживать алгоритм вручную, на бумаге или доске, также очень полезно, чтобы иметь возможность сделать это программически, поэтому вы можете увидеть значения ваших переменных на каждом шаге в выполнении программы для данный вклад.
Есть несколько способов достичь этого с Python. Мы рассмотрим два в этой статье.
Отслеживание переменных Python с использованием модуля SYS
Вот очень основной пример, показывающий, как проследить значения переменных в вызове функций с помощью Python sys модуль.
Пару вещей, чтобы отметить:
Если вы хотите проследить код, который не находится в функции, вам нужно «обмануть», поместив его в такие функции, как
Главная ()как в примере ниже. Это потому, чтотрассировкаФункция данных работает, проверяя кадры вызовов функций.Когда вы назвали функцию, которую вы хотите отследить, вам нужно добавить
sys.settrace (нет)Из вас получится много дополнительных продуктов, которые, вероятно, не имеют большого смысла.
import sys
def trace(frame, event, arg_unused):
print((event, frame.f_lineno, frame.f_locals))
return trace
def main():
x = 10
y = 20
sys.settrace(trace)
main()
sys.settrace(None)
Выход:
('call', 9, {})
('line', 10, {})
('line', 11, {'x': 10})
('return', 11, {'x': 10, 'y': 20})
>>>
и так, что здесь происходит?
Ну, мы сказали Python использовать нашу пользовательскую функцию трассировка () Чтобы произвести след любых функций, которые мы производим. Так что когда хорошо звоните Главная () Трассировка создана и выводится. Если вы внимательно посмотрите на вывод для данной функции, вы можете увидеть линейный список событие , Бенено (номер линии) и F_LOCALS – I.e. Локальные переменные для выполнения функции в настоящее время выполняются.
Довольно круто да?
Давайте посмотрим на более сложный пример.
Отслеживание функции фибоначчи в Python
import sys
def trace(frame, event, arg_unused):
print((event, frame.f_lineno, frame.f_locals))
return trace
sys.settrace(trace)
def fibonacci_iterative(n):
a, b = 0, 1
for i in range(n):
a, b = b, a + b
return a
fibonacci_iterative(4)
sys.settrace(None)
Выход:
('call', 12, {'n': 4})
('line', 13, {'n': 4})
('line', 14, {'n': 4, 'a': 0, 'b': 1})
('line', 15, {'n': 4, 'a': 0, 'b': 1, 'i': 0})
('line', 14, {'n': 4, 'a': 1, 'b': 1, 'i': 0})
('line', 15, {'n': 4, 'a': 1, 'b': 1, 'i': 1})
('line', 14, {'n': 4, 'a': 1, 'b': 2, 'i': 1})
('line', 15, {'n': 4, 'a': 1, 'b': 2, 'i': 2})
('line', 14, {'n': 4, 'a': 2, 'b': 3, 'i': 2})
('line', 15, {'n': 4, 'a': 2, 'b': 3, 'i': 3})
('line', 14, {'n': 4, 'a': 3, 'b': 5, 'i': 3})
('line', 16, {'n': 4, 'a': 3, 'b': 5, 'i': 3})
('return', 16, {'n': 4, 'a': 3, 'b': 5, 'i': 3})
>>>
Отслеживание рекурсивной функции звонков в Python
Еще одна ситуация, когда вы можете отследить выполнение программы, – это лучше понять, что происходит, когда Рекурсивная функция называется. Вы можете прочитать Подробнее о рекурсии здесь Отказ
Это может быть достигнуто с использованием вышеуказанного метода, как, например, в следующем примере:
import sys
def trace(frame, event, arg_unused):
print((event, frame.f_lineno, frame.f_locals))
return trace
sys.settrace(trace)
def fibonacci_recursive(n):
if n < 2:
return n
return fibonacci_recursive(n - 1) + fibonacci_recursive(n - 2)
fibonacci_recursive(4)
sys.settrace(None)
Выход:
('call', 12, {'n': 4})
('line', 13, {'n': 4})
('line', 15, {'n': 4})
('call', 12, {'n': 3})
('line', 13, {'n': 3})
('line', 15, {'n': 3})
('call', 12, {'n': 2})
('line', 13, {'n': 2})
('line', 15, {'n': 2})
('call', 12, {'n': 1})
('line', 13, {'n': 1})
('line', 14, {'n': 1})
('return', 14, {'n': 1})
('call', 12, {'n': 0})
('line', 13, {'n': 0})
('line', 14, {'n': 0})
('return', 14, {'n': 0})
('return', 15, {'n': 2})
('call', 12, {'n': 1})
('line', 13, {'n': 1})
('line', 14, {'n': 1})
('return', 14, {'n': 1})
('return', 15, {'n': 3})
('call', 12, {'n': 2})
('line', 13, {'n': 2})
('line', 15, {'n': 2})
('call', 12, {'n': 1})
('line', 13, {'n': 1})
('line', 14, {'n': 1})
('return', 14, {'n': 1})
('call', 12, {'n': 0})
('line', 13, {'n': 0})
('line', 14, {'n': 0})
('return', 14, {'n': 0})
('return', 15, {'n': 2})
('return', 15, {'n': 4})
>>>
Это нормально до точки, но есть способ получить более четкий след для рекурсивных алгоритмов.
Чтобы использовать его, создайте файл со следующим кодом в одной и той же папке, что и где рекурсивный код, который вы хотите отслеживать:
# trace_recursion.py
from functools import wraps
def trace(func):
# Store function name, for later use
func_name = func.__name__
separator = '| ' # Used in trace display
# Set the current recursion depth
trace.recursion_depth = 0
@wraps(func)
def traced_func(*args, **kwargs):
# Display function call details
print(f'{separator * trace.recursion_depth}|-- {func_name}({", ".join(map(str, args))})')
# Begin recursing
trace.recursion_depth += 1
result = func(*args, **kwargs)
# Exit current level
trace.recursion_depth -= 1
# Display return value
print(f'{separator * (trace.recursion_depth + 1)}|-- return {result}')
return result
return traced_func
Тогда вы можете использовать трассировка Функция помощника, чтобы получить приятное, легко читать представление рекурсивных вызовов, их аргументов и их возвратных значений.
Например:
from trace_recursion import trace
def factorial(n):
if n <= 1:
# Base case
return 1
else:
# Recursive case
return n * factorial(n - 1)
factorial = trace(factorial)
factorial(5)
``
Чтобы получить супер удобный выход:
|-- factorial(5) | |-- factorial(4) | | |-- factorial(3) | | | |-- factorial(2) | | | | |-- factorial(1) | | | | | |-- return 1 | | | | |-- return 2 | | | |-- return 6 | | |-- return 24 | |-- return 120 >>>
Эта статья показала вам два способа, которыми вы можете получить Python, чтобы дать вам ценную информацию о ваших программах, отслеживая их выполнение. Попробуйте эти методы для себя своими собственными программами, если вам необходимо разработать ваше понимание определенного алгоритма или отладка ошибки логики.
Счастливые вычисления!