测量时间的Python上下文管理器

时间:2015-11-29 19:29:55

标签: python with-statement

我正在努力制作一段代码,允许测量在“with”语句中花费的时间,并将测量的时间(浮点数)分配给“with”语句中提供的变量。

import time

class catchtime:
    def __enter__(self):
        self.t = time.clock()
        return 1

    def __exit__(self, type, value, traceback):
        return time.clock() - self.t

with catchtime() as t:
    pass

此代码离开t=1而不是clock()调用之间的区别。如何解决这个问题?我需要一种从exit方法中分配新值的方法。

PEP 343 describes更详细地说明了竞赛经理是如何运作的,但我不了解其中的大部分内容。

3 个答案:

答案 0 :(得分:4)

解决了(差不多)。结果变量是可强制的并且可以转换为浮点数(但不是浮点数)。

class catchtime:
    def __enter__(self):
        self.t = time.clock()
        return self

    def __exit__(self, type, value, traceback):
        self.e = time.clock()

    def __float__(self):
        return float(self.e - self.t)

    def __coerce__(self, other):
        return (float(self), other)

    def __str__(self):
        return str(float(self))

    def __repr__(self):
        return str(float(self))

with catchtime() as t:
    pass

print t
print repr(t)
print float(t)
print 0+t
print 1*t

1.10000000001e-05
1.10000000001e-05
1.10000000001e-05
1.10000000001e-05
1.10000000001e-05

答案 1 :(得分:4)

您无法将时间分配给t。如PEP中所述,您在as子句中指定的变量(如果有)将被分配调用__enter__的结果,而不是__exit__。换句话说,t仅在with块的 start 处分配,而不是在末尾。

您可以做的是更改__exit__,以便不是返回值,而是self.t = time.clock() - self.t。然后,在with块完成后,上下文管理器的t属性将保留已用时间。

为了实现这一目标,您还希望从self返回1而不是__enter__。使用1确定您要实现的目标。

所以它看起来像这样:

class catchtime(object):
    def __enter__(self):
        self.t = time.clock()
        return self

    def __exit__(self, type, value, traceback):
        self.t = time.clock() - self.t

with catchtime() as t:
    time.sleep(1)

print(t.t)

打印出一个非常接近1的值。

答案 2 :(得分:2)

以下是使用contextmanager

的示例
from time import perf_counter
from contextlib import contextmanager

@contextmanager
def catchtime() -> float:
    start = perf_counter()
    yield lambda: perf_counter() - start


with catchtime() as t:
    import time
    time.sleep(1)

print(f"Execution time: {t():.4f} secs")

输出:

执行时间:1.0014秒