Python profiling using line_profiler - clever way to remove @profile statements on-the-fly?

Instead of removing the @profile decorator lines, provide your own pass-through no-op version.

You can add the following code to your project somewhere:

try:
    # Python 2
    import __builtin__ as builtins
except ImportError:
    # Python 3
    import builtins

try:
    builtins.profile
except AttributeError:
    # No line profiler, provide a pass-through version
    def profile(func): return func
    builtins.profile = profile

Import this before any code using the @profile decorator and you can use the code with or without the line profiler being active.

Because the dummy decorator is a pass-through function, execution performance is not impacted (only import performance is every so lightly affected).

If you don't like messing with built-ins, you can make this a separate module; say profile_support.py:

try:
    # Python 2
    import __builtin__ as builtins
except ImportError:
    # Python 3
    import builtins

try:
    profile = builtins.profile
except AttributeError:
    # No line profiler, provide a pass-through version
    def profile(func): return func

(no assignment to builtins.profile) and use from profile_support import profile in any module that uses the @profile decorator.


You don't need to import __builtins__/builtins or LineProfiler at all, you can simply rely on a NameError when trying to lookup profile:

try:
    profile
except NameError:
    profile = lambda x: x

However this needs to be included in every file that uses profile, but it doesn't (permanently) alter the global state (builtins) of Python.


A comment that grew to become a variant of @Martijin Pieters answer.

I prefer not to involve __builtin__ at all. W/o a comment, it would be practically impossible for someone else to guess that line_profiler is involved, w/o a priori knowing this.

Looking at kernprof line 199, it suffices to instantiate LineProfiler.

try:
    from line_profiler import LineProfiler
    profile = LineProfiler()
except ImportError:
    def profile(func):
        return func

Importing (explicit) is better than globally modifying builtins (implicit). If the profiling decorators are permanent, then their origin should be clear in the code itself.

In presence of line_profiler, the above approach will wrap the decorated functions with profilers on every run, irrespective of whether run by kernprof. This side-effect may be undesired.