#python #python-3.x #debugging #stack-trace
#python #python-3.x #отладка #трассировка стека
Вопрос:
При многократном вызове одной и той же функции в одной строке. Возможно ли для устранения неполадок использовать трассировку или библиотеку sys, чтобы определить, какой из них выполняется в данный момент?
Редактировать: Пожалуйста, не предоставляйте обходной путь. Я знаю все, что мне нужно знать о том, как обойти эту проблему. Что я хотел бы знать, так это то, есть ли способ найти более точную информацию о состоянии синтаксического анализа / выполнения, чем просто номер строки вызывающей инструкции.
Давайте рассмотрим этот пример:
#!/usr/bin/python3
# coding: UTF-8
def fn(var):
import traceback
print(repr(traceback.extract_stack()[-2]))
return var 1
a = b = 4
print(fn(a) fn(b))
Запуск этого в режиме ожидания приведет к записи :
RESTART: /.../python/framesummary.py
<FrameSummary file /.../python/framesummary.py, line 11 in <module>>
<FrameSummary file /.../python/framesummary.py, line 11 in <module>>
10
Есть ли какой-либо способ узнать внутри fn
функции, выполняется ли она в данный момент fn(a)
или fn(b)
?
Правка2 :
Я добавил случай, который показывает, что порядок вызова не может быть использован
#!/usr/bin/python3
# coding: UTF-8
def fn(var):
import traceback
stack = traceback.extract_stack()
print(repr(stack[-2]))
print("code = '" stack[-2][-1] "'")
import sys
calling_frame = sys._getframe(1)
print("lasti =", calling_frame.f_lasti)
print()
return var 1
a = b = 4
print("case = sum", fn(a) fn(b), "n")
for boole in False, True:
print("case =", boole, fn(a) if boole else fn(b), "n")
выведет:
RESTART: /.../python/framesummary cleaned.py
<FrameSummary file /.../python/framesummary cleaned.py, line 18 in <module>>
code = 'print("case = sum", fn(a) fn(b), "n")'
lasti = 34
<FrameSummary file /.../python/framesummary cleaned.py, line 18 in <module>>
code = 'print("case = sum", fn(a) fn(b), "n")'
lasti = 43
case = sum 10
<FrameSummary file /.../python/framesummary cleaned.py, line 20 in <module>>
code = 'print("case =", boole, fn(a) if boole else fn(b), "n")'
lasti = 100
case = False 5
<FrameSummary file /.../python/framesummary cleaned.py, line 20 in <module>>
code = 'print("case =", boole, fn(a) if boole else fn(b), "n")'
lasti = 88
case = True 5
что было бы неплохо, так это иметь указание первого символа вызова или способ перекомпиляции кода, чтобы получить значения lasti, соответствующие каждому вызову.
Очевидно, что анализ результата показывает, что значения lasti коррелируют с позицией, но до сих пор я не нашел способа узнать эту взаимосвязь перед выполнением программы :
lasti = 34 => (line, column) = (18, 33) (or pos=29 in unindented string⁽¹⁾)
lasti = 43 => (line, column) = (18, 39) (or pos=35 in unindented string⁽¹⁾)
lasti = 88 => (line, column) = (20, 40) (or pos=32 in unindented string⁽¹⁾)
lasti = 100 => (line, column) = (20, 60) (or pos=52 in unindented string⁽¹⁾)
(1) как указано в stack[-2][-1]
Комментарии:
1. Вы могли бы добавить дополнительный поверхностный аргумент, который вы передаете полностью (или его модифицированную версию). Итак, вы могли бы назвать это так:
fn(a, 'a')
где ваш fbn определен какdef fn(varval, varname):...
Это может быть полезно для отладки, но зачем вам это действительно нужно? Проверка фрейма стека внутри простой функции приведет к тому, что ваша программа будет работать намного медленнее.2. Как бы вы их вообще различали?
a
иb
являются псевдонимами одной и той же переменной. Python гарантирует порядок вычисления слева направо , поэтомуfn(a)
всегда запускается первым, иf_lasti
объекта frame может сообщить вам индекс байт-кода, выполняемого на любом заданном уровне фрейма, но я не уверен, как вы хотите визуально различать эти вещи.3. @leonid, я хотел бы создать чистую функцию, которая помогла бы учащимся просматривать переменные в удобочитаемом виде, но не отвлекая их от реальной задачи.
4. Вы используете CPython. Вы просто не распознаете это.
5. @Camion: CPython — это эталонный интерпретатор Python (тот, который вы получаете от python.org/downloads и тот, который установлен по умолчанию в большинстве дистрибутивов Linux / BSD). IDLE поставляется с ним, чтобы обеспечить простую среду разработки, вот и все. Если вы явно не установили PyPy, IronPython или Jython, вы используете CPython.
Ответ №1:
Вы можете отправить уникальный и случайный идентификатор в качестве дополнительного параметра и добавить его в журналы.
Идентификатор поможет вам отследить источник.
a = b = 4
id1 = some random no.
id2 = some random no.
print(fn(a, id1) fn(b, id2))
Комментарии:
1. Я хотел бы знать, есть ли способ сделать это только на основе внутренних структур pythons.
Ответ №2:
Я думаю, вам лучше всего было бы научиться использовать pdb. Хотя вы могли бы изменить код, чтобы дать вам некоторый ограниченный самоанализ в запущенный код. Будет проще и, в конечном счете, более ценным получить работающий отладчик, позволяющий наблюдать за состоянием кода во время его оценки.
попробуйте pdb
def fn(var):
import pdb; pdb.set_trace()
return var 1
a = b = 4
print(fn(a) fn(b)
это откроет отладчик python и позволит вам выполнять такие действия, как use w
, что означает, где и в pdb печатает трассировку стека. Или l
которые показывают источник в текущей строке выполнения и т.д.
Это будет выглядеть примерно так
owen@lettuce:~ python temp.py
> /home/owen/temp.py(3)fn()
-> return var 1
(Pdb) w
/home/owen/temp.py(6)<module>()
-> print(fn(a) fn(b))
> /home/owen/temp.py(3)fn()
-> return var 1
(Pdb) l
1 def fn(var):
2 import pdb; pdb.set_trace()
3 -> return var 1
4
5 a = b = 4
6 print(fn(a) fn(b))
[EOF]
(Pdb)
Удачи. Надеюсь, это поможет.
Комментарии:
1. Привет @Owen. Как вы думаете, я мог бы использовать pdb для получения информации, которую я ищу, изнутри моего кода?
2. @Camion, я не совсем уверен, какую информацию ты пытаешься получить? Не могли бы вы уточнить? Также я не совсем уверен, что вы имеете в виду под
inside my code
3. Я не хочу иметь возможность точно указать изнутри fn (), какой вызов отвечал за текущее выполнение, без необходимости изменять синтаксис его вызова (т. Е. Не добавлять параметр устранения неоднозначности). До сих пор единственным связанным значением, которое я могу найти, является lasti , но я не нашел (пока) способа соотнести lasti с парой (строка, столбец)
4. Я добавил больше деталей в сообщение
5. Хотя я не слишком хорошо знаком с внутренней структурой фреймов стека, используя pdb и dir, вы можете взглянуть на объекты и попытаться извлечь из них некоторую полезную информацию. Например: dir(calling_frame) = [ … встроенные в python по умолчанию …, ‘f_back’, ‘f_builtins’, ‘f_code’, ‘f_exc_traceback’, ‘f_exc_type’, ‘f_exc_value’, ‘f_globals’, ‘f_lasti’, ‘f_lineno’, ‘f_locals’, ‘f_restricted’, ‘f_trace’]