Search code examples
pythonprofilingdecoratorpython-decorators

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


I want to use the excellent line_profiler, but only some of the time. To make it work I add

@profile

before every function call, e.g.

@profile
def myFunc(args):
    blah
    return

and execute

kernprof.py -l -v mycode.py args

But I don't want to have to put the @profile decorators in by hand each time, because most of the time I want to execute the code without them, and I get an exception if I try to include them, e.g.

mycode.py args

Is there a happy medium where I can dynamically have the decorators removed based on some condition switch/argument, without having to do things manually and/or modify each function too much?


Solution

  • 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.