装饰器来代替整个方法的特定代码行?

Dhr*_*hak 9 python

让我们假设一个简单的方法:

def test_method():
    a = 1
    b = 10000
    c = 20000
    sum1 = sum(range(a,b))
    sum2 = sum(range(b,c))
    return (sum1,sum2)
Run Code Online (Sandbox Code Playgroud)

要使用装饰器计时此方法,一个简单的装饰器将是:

from functools import wraps
def timed_decorator(f):
    @wraps(f)
    def wrapper(*args, **kwds):
        start = time.time()
        result = f(*args, **kwds)
        elapsed = (time.time() - start)*1000
        logger.debug("f::{0} t::{1:0.2f} ms".format(f.__name__, elapsed))
        return result
    return wrapper
Run Code Online (Sandbox Code Playgroud)

现在,如果我test_method想说第4 行的特定行sum1 = sum(range(a,b)),那么当前的实现涉及内联编码,如:

 def test_method():
        a = 1
        b = 10000
        c = 20000
        start = time.time()
        sum1 = sum(range(a,b)) # timing specific line or lines
        elapsed = (time.time() - start)*1000
        logger.debug("This part took::{1:0.2f} ms".format(elapsed))
        sum2 = sum(range(b,c))
        return (sum1,sum2)
Run Code Online (Sandbox Code Playgroud)

目的是使用装饰器来定时特定方法的行M到N而不修改方法中的代码.是否可以使用装饰器注入这样的逻辑?

Nik*_*s R 12

您可以使用上下文管理器.

import contextlib

@contextlib.contextmanager
def time_measure(ident):
    tstart = time.time()
    yield
    elapsed = time.time() - tstart
    logger.debug("{0}: {1} ms".format(ident, elapsed))
Run Code Online (Sandbox Code Playgroud)

在你的代码中,你就像使用它一样

with time_measure('test_method:sum1'):
    sum1 = sum(range(a, b))
Run Code Online (Sandbox Code Playgroud)

顺便说一下,如果你想改进你的代码,你可以使用高斯和公式(这里解释)而不是sum(range(a, b)).

def sum_range(a, b):
    r_a = (a ** 2 + a) / 2 - a
    r_b = (b ** 2 + b) / 2 - b
    return r_b - r_a
Run Code Online (Sandbox Code Playgroud)

  • 如果不修改原始代码,则无法执行此操作.从逻辑上判断,只有当它是一个完整的单元时才可以在外部进行时间编码,比如`module`,`function`等.至于一些代码行,@ Niklas R给出了一个非常好的pythonic方法来实现你的目标. (7认同)