Имейте в виду, что независимо от сценария причина всегда одинакова в .NET:
Вы пытаетесь использовать ссылочную переменную, значение которой
Nothing
/null
. Если для ссылочной переменной значениеNothing
/null
, это означает, что на самом деле оно не содержит ссылку на экземпляр любого объекта, который существует в куче.Вы либо никогда не присваивали какую-либо переменную, никогда не создавали экземпляр значения, присвоенного переменной, или вы вручную устанавливали переменную, равную
blockquote>Nothing
/null
, или вы вызывали функцию, которая установите для этой переменной значениеNothing
/null
.
Вы можете сделать это с помощью функции трассировки (реквизиты для 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()
. Можно использовать ту же самую функцию трассировки; это просто, что функция профиля вызывается только при вводе или выходе функции, поэтому функция внутри функции выполняется на полной скорости.
import traceback
def foo():
traceback.print_stack()
def bar():
foo()
def car():
bar():
car()
File "<string>", line 1, in <module>
File "C:\Python27\lib\idlelib\run.py", line 97, in main
ret = method(*args, **kwargs)
File "C:\Python27\lib\idlelib\run.py", line 298, in runcode
exec code in self.locals
File "<pyshell#494>", line 1, in <module>
File "<pyshell#493>", line 2, in car
File "<pyshell#490>", line 2, in bar
File "<pyshell#486>", line 2, in foo
Еще один хороший инструмент, который нужно знать, это модуль trace :
$ cat foo.py
def foo():
bar()
def bar():
print "in bar!"
foo()
$ python -m trace --listfuncs foo.py
in bar!
functions called:
filename: /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/trace.py, modulename: trace, funcname: _unsettrace
filename: foo.py, modulename: foo, funcname:
filename: foo.py, modulename: foo, funcname: bar
filename: foo.py, modulename: foo, funcname: foo
$python -m trace --trace foo.py
--- modulename: foo, funcname:
foo.py(1): def foo():
foo.py(4): def bar():
foo.py(7): foo()
--- modulename: foo, funcname: foo
foo.py(2): bar()
--- modulename: foo, funcname: bar
foo.py(5): print "in bar!"
in bar!
--- modulename: trace, funcname: _unsettrace
trace.py(80): sys.settrace(None)
Вы можете использовать settrace, как описано здесь: Трассировка кода python . Используйте версию в конце страницы. Я вставляю код этой страницы в свой код, чтобы точно увидеть, какие строки выполняются при работе моего кода. Вы также можете фильтровать так, чтобы вы видели только имена названных функций.
Есть несколько вариантов. Если отладчика недостаточно, вы можете установить функцию трассировки с помощью sys.settrace()
. Эта функция будет по существу вызываться в каждой строке исполняемого кода Python, но легко идентифицировать вызовы функций - см. Связанную документацию.
Вас также может заинтересовать trace
, хотя он не делает именно то, что вы просили. Обязательно загляните в опцию --trackcalls
.