Вы можете сделать это с помощью функции трассировки (обратитесь к Spacedman для улучшения исходной версии этого, чтобы отследить возвраты и использовать некоторые хорошие отступы):
def tracefunc(frame, event, arg, indent=[0]):
if event == "call":
indent[0] += 2
print("-" * indent[0] + "> call function", frame.f_code.co_name)
elif event == "return":
print("<" + "-" * indent[0], "exit function", frame.f_code.co_name)
indent[0] -= 2
return tracefunc
import sys
sys.settrace(tracefunc)
main() # or whatever kicks off your script
Обратите внимание, что объект кода функции обычно имеет то же имя, что и связанная функция, но не всегда, поскольку функции могут создаваться динамически. К сожалению, Python не отслеживает объекты функций в стеке (я иногда мечтал представить патч для этого). Тем не менее, это, безусловно, "достаточно хорошо" в большинстве случаев.
Если это становится проблемой, вы можете извлечь «настоящее» имя функции из исходного кода - Python отслеживает имя файла и номер строки - или попросить сборщик мусора выяснить, какой объект функции ссылается на объект кода. Может быть несколько функций, совместно использующих объект кода, но любое из их имен может быть достаточно хорошим.
Возвращаясь к этому вопросу четыре года спустя, я должен упомянуть, что в Python 2.6 и более поздних версиях вы можете повысить производительность, используя sys.setprofile()
вместо sys.settrace()
. Та же функция трассировки может быть использована; просто функция профиля вызывается только при входе или выходе из функции, поэтому то, что находится внутри функции, выполняется на полной скорости.