使用line_profiler的Python评测-动态删除@profile语句的聪明方法



我想使用出色的line_profiler,但只是部分时间。为了让它发挥作用,我添加了

@profile

在每次函数调用之前,例如

@profile
def myFunc(args):
    blah
    return

并执行

kernprof.py -l -v mycode.py args

但我不想每次都手动放入@profile装饰器,因为大多数时候我都想在没有它们的情况下执行代码,如果我试图包含它们,我会遇到异常,例如

mycode.py args

有没有一种愉快的媒介,我可以根据一些条件切换/参数动态地删除装饰器,而不必手动操作和/或过多地修改每个函数?

与其删除@profile装饰器行,不如提供您自己的直通无操作版本。

您可以将以下代码添加到您的项目中:

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

使用@profile装饰器在任何代码之前导入它,您可以在激活或不激活行探查器的情况下使用代码。

因为伪decorator是一个传递函数,所以执行性能不会受到影响(只有导入性能受到轻微影响)。

如果你不喜欢破坏内置模块,你可以把它做成一个单独的模块;比如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

(没有对builtins.profile赋值),并在任何使用@profile装饰器的模块中使用from profile_support import profile

您根本不需要导入__builtins__/builtinsLineProfiler,您可以在尝试查找profile:时简单地依赖NameError

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

然而,这需要包含在使用profile的每个文件中,但它不会(永久)改变Python的全局状态(内置)。

一条评论,后来成为@Martijin Pieters答案的变体。

我宁愿根本不涉及__builtin__。在没有评论的情况下,其他人几乎不可能猜测line_profiler参与其中,也不可能事先知道这一点。

查看kernprof行199,实例化LineProfiler就足够了。

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

导入(显式)比全局修改builtins(隐式)要好。如果评测装饰器是永久性的,那么它们的来源应该在代码本身中是明确的。

在存在line_profiler的情况下,无论是否由kernprof运行,上述方法都将在每次运行时用profiler封装修饰函数。这种副作用可能是不希望的。

我使用的是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

其他答案都是正确的,但在尝试"素数";类似CCD_ 21的脚本。这样初始化脚本可能很有用,例如,当您尝试使用numba优化函数时,并且您不想在编译(或从文件系统缓存加载,即使使用numbas-cache=True param,这仍然会有很大的开销)时使行计时偏误。

问题是,安装运行会套住所有@profile装饰器,并使它们在评测运行中变得毫无意义。

我通过将try转移到实际的decorator运行来解决这个问题,如下所示:

def profile2(f):
    def s(*args, **kwargs):
        try:
            return profile(f)(*args, **kwargs)
        except NameError:
            return f(*args, **kwargs)
    return s

并用CCD_ 24对我的所有功能进行了装饰。

最新更新