Python Наблюдение за вызовами str с помощью sys.setprofile и проверки фреймов

Я новичок в самоанализе фреймов 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 или встроенные вызовы.

Вы видели эта почта? Это не выглядит обнадеживающим. Причина, по которой не следует передавать вызовы C функции трассировки, заключается в том, что трассировка существует для поддержки pdb и других отладчиков, а pdb заботится только о трассировке через код Python. Так что документы должны быть обновлены. (Гуидо ван Россум, янв 2018)

Jacques Gaudin 08.06.2018 20:32

Даже если бы вы могли отследить свои звонки на str, он не охватил бы такие вещи, как "%s"%x, "".join(…), так далее.

Davis Herring 08.06.2018 20:45
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
6
2
255
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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 для достижения тех же результатов.

Другие вопросы по теме