Я новичок в самоанализе фреймов Python, и я пытаюсь установить профилировщик или трассировщик, чтобы отслеживать вызовы функций str. У меня есть средства трассировки различными способами, но я думаю, что мне не хватает некоторых ключевых понятий, касающихся интроспекции кадра и того, как получить имена встроенных функций (например, str).
def test_trace():
sys.setprofile(trace_calls)
hi = str('hellllo')
stuff = []
for i in range(10):
stuff.append(str(random.randrange(0, 10000000000)))
print(hi)
os._exit(0)
def trace_calls(frame, event, arg):
'''
if event not in ('call', 'c_call'):
return
'''
stack = collections.deque()
stack.appendleft(_expand_arg(arg) + _expand_frame(frame))
while frame.f_back is not None:
stack.appendleft(_expand_arg(arg) + _expand_frame(frame))
frame = frame.f_back
print('-' * 100)
for frame in stack:
print(frame)
def _expand_arg(arg):
if arg is None:
return ()
return (
# arg.__name__,
)
def _expand_frame(frame):
code = frame.f_code
c_class = ''
c_module = ''
if 'self' in frame.f_locals:
c_class = frame.f_locals['self'].__class__.__name__
c_module = frame.f_locals['self'].__class__.__module__
return (
code.co_filename,
frame.f_lineno,
frame.f_trace,
code.co_name,
code.co_firstlineno,
c_class,
c_module,
)
Когда я запускаю test_trace(), я не вижу упоминания о каких-либо вызовах str ни в одном из профилированных событий. Я ожидал увидеть упоминания str или <string> в некоторых стеках вызовов, но вижу только случайные вызовы:
$ ipython
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.4.0 -- An enhanced Interactive Python. Type '?' for help.
('/home/ubuntu/.virtualenvs/papm/lib/python3.5/site-packages/IPython/__init__.py', 125, None, 'start_ipython', 99, '', '')
('/home/ubuntu/.virtualenvs/papm/lib/python3.5/site-packages/traitlets/config/application.py', 658, None, 'launch_instance', 650, '', '')
('/home/ubuntu/.virtualenvs/papm/lib/python3.5/site-packages/IPython/terminal/ipapp.py', 356, None, 'start', 350, 'TerminalIPythonApp', 'IPython.terminal.ipapp')
('/home/ubuntu/.virtualenvs/papm/lib/python3.5/site-packages/IPython/terminal/interactiveshell.py', 485, None, 'mainloop', 478, 'TerminalInteractiveShell', 'IPython.terminal.in
teractiveshell')
('/home/ubuntu/.virtualenvs/papm/lib/python3.5/site-packages/IPython/terminal/interactiveshell.py', 476, None, 'interact', 458, 'TerminalInteractiveShell', 'IPython.terminal.in
teractiveshell')
('/home/ubuntu/.virtualenvs/papm/lib/python3.5/site-packages/IPython/core/interactiveshell.py', 2662, None, 'run_cell', 2636, 'TerminalInteractiveShell', 'IPython.terminal.inte
ractiveshell')
('/home/ubuntu/.virtualenvs/papm/lib/python3.5/site-packages/IPython/core/interactiveshell.py', 2785, None, '_run_cell', 2669, 'TerminalInteractiveShell', 'IPython.terminal.int
eractiveshell')
('/home/ubuntu/.virtualenvs/papm/lib/python3.5/site-packages/IPython/core/interactiveshell.py', 2909, None, 'run_ast_nodes', 2835, 'TerminalInteractiveShell', 'IPython.terminal
.interactiveshell')
('/home/ubuntu/.virtualenvs/papm/lib/python3.5/site-packages/IPython/core/interactiveshell.py', 2963, None, 'run_code', 2933, 'TerminalInteractiveShell', 'IPython.terminal.inte
ractiveshell')
('<ipython-input-2-a29a88804d82>', 1, None, '<module>', 1, '', '')
('/vagrant_data/github.com/dm03514/python-apm/pythonapm/instruments/monkey.py', 35, None, 'test_trace', 30, '', '')
('/home/ubuntu/.virtualenvs/papm/lib/python3.5/random.py', 194, None, 'randrange', 170, 'Random', 'random')
('/home/ubuntu/.virtualenvs/papm/lib/python3.5/random.py', 232, None, '_randbelow', 220, 'Random', 'random')
('/home/ubuntu/.virtualenvs/papm/lib/python3.5/random.py', 232, None, '_randbelow', 220, 'Random', 'random')
('/home/ubuntu/.virtualenvs/papm/lib/python3.5/site-packages/IPython/__init__.py', 125, None, 'start_ipython', 99, '', '')
('/home/ubuntu/.virtualenvs/papm/lib/python3.5/site-packages/traitlets/config/application.py', 658, None, 'launch_instance', 650, '', '')
('/home/ubuntu/.virtualenvs/papm/lib/python3.5/site-packages/IPython/terminal/ipapp.py', 356, None, 'start', 350, 'TerminalIPythonApp', 'IPython.terminal.ipapp')
('/home/ubuntu/.virtualenvs/papm/lib/python3.5/site-packages/IPython/terminal/interactiveshell.py', 485, None, 'mainloop', 478, 'TerminalInteractiveShell', 'IPython.terminal.in
teractiveshell')
('/home/ubuntu/.virtualenvs/papm/lib/python3.5/site-packages/IPython/terminal/interactiveshell.py', 476, None, 'interact', 458, 'TerminalInteractiveShell', 'IPython.terminal.in
teractiveshell')
('/home/ubuntu/.virtualenvs/papm/lib/python3.5/site-packages/IPython/core/interactiveshell.py', 2662, None, 'run_cell', 2636, 'TerminalInteractiveShell', 'IPython.terminal.inte
ractiveshell')
('/home/ubuntu/.virtualenvs/papm/lib/python3.5/site-packages/IPython/core/interactiveshell.py', 2785, None, '_run_cell', 2669, 'TerminalInteractiveShell', 'IPython.terminal.int
eractiveshell')
('/home/ubuntu/.virtualenvs/papm/lib/python3.5/site-packages/IPython/core/interactiveshell.py', 2909, None, 'run_ast_nodes', 2835, 'TerminalInteractiveShell', 'IPython.terminal
.interactiveshell')
('/home/ubuntu/.virtualenvs/papm/lib/python3.5/site-packages/IPython/core/interactiveshell.py', 2963, None, 'run_code', 2933, 'TerminalInteractiveShell', 'IPython.terminal.inte
ractiveshell')
('<ipython-input-2-a29a88804d82>', 1, None, '<module>', 1, '', '')
('/vagrant_data/github.com/dm03514/python-apm/pythonapm/instruments/monkey.py', 35, None, 'test_trace', 30, '', '')
('/home/ubuntu/.virtualenvs/papm/lib/python3.5/random.py', 194, None, 'randrange', 170, 'Random', 'random')
('/home/ubuntu/.virtualenvs/papm/lib/python3.5/random.py', 194, None, 'randrange', 170, 'Random', 'random')
Я видел строковые вызовы во встроенных профилях Python поэтому я попытался посмотреть, как они получают имена функций c в случае, если str делегировал вызов c.
Я попытался получить вызовы функции c, проверив arg (как с setprofile, так и с settrace, но он также не показал никаких строковых вызовов
if event == "c_call":
self.c_func_name = arg.__name__
Кто-нибудь знаком с тем, как отслеживать питон str или встроенные вызовы.
Даже если бы вы могли отследить свои звонки на str, он не охватил бы такие вещи, как "%s"%x, "".join(…), так далее.






When I run test_trace() I see no mention of any str calls in any of the profiled events.
Это потому, что str() - это тип объекта, полностью определенный в C. Отслеживается только вызовы функций, а не вызовы типов, поэтому событие c_call не выдается.
Вы можете обойти это, заменив встроенный str; вы можете изменить встроенные функции Python через builtins модуль:
import builtins
orig_str = builtins.str
def traceable_str(*args):
return orig_str(*args)
builtins.str = traceable_str
Теперь вы можете видеть, что вызовы traceable_str передаются в функцию профилирования.
Однако учтите, что будет отслеживаться только звонки из кода Python в str()! Все, что реализовано на C, например функция print(), даже не вызывает встроенную функцию str(), а просто использует API C для достижения тех же результатов.
Вы видели эта почта? Это не выглядит обнадеживающим. Причина, по которой не следует передавать вызовы C функции трассировки, заключается в том, что трассировка существует для поддержки pdb и других отладчиков, а pdb заботится только о трассировке через код Python. Так что документы должны быть обновлены. (Гуидо ван Россум, янв 2018)