Профилирование python с использованием line_profiler - умный способ удаления операторов @profile на лету?
Я хочу использовать отличный line_profiler, но только некоторое время. Чтобы сделать это, я добавляю
@profile
перед каждым вызовом функции, например
@profile
def myFunc(args):
blah
return
и выполните
kernprof.py -l -v mycode.py args
Но я не хочу, чтобы каждый раз декорировать @profile
вручную, потому что большую часть времени я хочу выполнить код без них, и получаю исключение, если я пытаюсь их включить, например,
mycode.py args
Есть ли счастливая среда, где я могу динамически удалять декораторов на основе какого-либо условия switch/argument, без необходимости делать что-то вручную и/или изменять каждую функцию слишком много?
Ответы
Ответ 1
Вместо того, чтобы удалять строки декоратора @profile
, укажите свою собственную сквозную версию no-op.
В проект можно добавить следующий код:
import __builtin__
try:
__builtin__.profile
except AttributeError:
# No line profiler, provide a pass-through version
def profile(func): return func
__builtin__.profile = profile
Импортируйте это перед любым кодом с помощью декоратора @profile
, и вы можете использовать код с активным профилиром линии или без него.
Поскольку фиктивный декоратор является сквозной функцией, производительность исполнения не затрагивается (только импортная производительность настолько сильно затронута).
Если вам не нравится возиться со встроенными модулями, вы можете сделать это отдельным модулем; скажем profile_support.py
:
import __builtin__
try:
profile = __builtin__.profile
except AttributeError:
# No line profiler, provide a pass-through version
def profile(func): return func
(без присвоения __builtin__.profile
) и используйте from profile_support import profile
в любом модуле, который использует декоратор @profile
.
Ответ 2
Комментарий, который вырос, чтобы стать вариантом ответа @Martijin Pieters.
Я предпочитаю вообще не включать __builtin__
. Без комментария было бы практически невозможно, чтобы кто-то еще догадался, что задействован line_profiler
, без априори, зная это.
Рассматривая kernprof
line 199, достаточно создать экземпляр LineProfiler
.
try:
from line_profiler import LineProfiler
profile = LineProfiler()
except ImportError:
def profile(func):
return func
Импорт (явный) лучше, чем глобальная модификация builtins
(неявная). Если профилирующие декораторы являются постоянными, то их происхождение должно быть ясным в самом коде.
При наличии line_profiler
вышеприведенный подход обертывает украшенные функции профайлерами при каждом запуске, независимо от того, выполняется ли оно kernprof
. Этот побочный эффект может быть нежелательным.
Ответ 3
Вам не нужно импортировать __builtins__
/builtins
или LineProfiler
вообще, вы можете просто полагаться на NameError
при поиске profile
:
try:
profile
except NameError:
profile = lambda x: x
Однако это должно быть включено в каждый файл, который использует profile
, но он (постоянно) не изменяет глобальное состояние (встроенные) Python.
Ответ 4
Я использую следующую модифицированную версию с Python 3.4
try:
import builtins
profile = builtins.__dict__['profile']
except KeyError:
# No line profiler, provide a pass-through version
def profile(func): return func