2

我想计时一些取决于某些设置的代码。设置代码看起来有点像这样:

>>> b = range(1, 1001)

我想要计时的代码看起来像这样:

>>> sorted(b)

除了我的代码使用与排序不同的功能。但现在这并不重要。

无论如何,只要我将字符串传递给timeit,我就知道如何为这段代码计时:

>>> import timeit
>>> t = timeit.Timer("sorted(b)", "b = range(1, 1001)")
>>> min(t.repeat(3, 100))

如何使用 setup callable 并将其放入 stmt callable 可以访问的命名空间中?

换句话说,我如何做与上面的代码相同的事情,但使用可调用对象,而不是包含可调用对象的字符串?

顺便说一句,这里更大的目标是重用我的单元测试中的代码来衡量性能:

import unittest
class TestSorting(unittest.TestCase):

    def setUp(self):
        self.b = range(1, 1001)

    def test_sorted(self):
        sorted(self.b)

我希望做一点工作。timeit 设置需要创建一个 TestSorting 实例,并且 stmt 代码必须以某种方式使用该特定实例。

一旦我了解了如何让 timeit 设置将内容放入与 timeit stmt 相同的命名空间中,我将研究如何将 unittest.TestCase 实例转换为可以直接输入 timeit.Timer 的内容。

马特

4

2 回答 2

1

在 2.6 中,您可以“照做”,根据文档

在 2.6 版更改stmtand setup参数现在也可以采用不带参数的可调用对象。这会将对它们的调用嵌入到计时器函数中,然后由timeit(). 请注意,在这种情况下,由于额外的函数调用,时间开销会稍大一些。

你还在使用旧版本的 Python 吗?在这种情况下,我建议使用 Python 2.6 的timer.py源代码并将它们“向后移植”到您坚持使用的版本——如果该版本是 2.5 应该不难(您需要返回的时间越远越难,当然)。对于“生产”代码,我通常不建议这样做,但对于支持测试、调试、性能测量等的代码来说,它是相当不错的。

于 2010-05-12T14:43:21.900 回答
1

我在这里问了这个问题的一个变体,也得到了一个没有解决我问题的答案。我相信我们都没有用 Pythonic 来表达这个问题。

我不知道这是否是一种 hack、解决方法或应该如何完成,但它确实有效:

>>> import timeit
>>> b = range(1, 1001)
>>> t = timeit.Timer('sorted(b)', setup='from __main__ import b')
>>> t.repeat(3, 100)
[0.0024309158325195312, 0.0024671554565429688, 0.0024020671844482422]
# was it really running 'sorted(b)'? let's compare'
>>> t = timeit.Timer('pass', setup='from __main__ import b')
>>> t.repeat(3, 100) 
[3.0994415283203125e-06, 2.1457672119140625e-06, 1.9073486328125e-06] 
# teeny times for 'pass', 'sorted(b)' took more time

我已经阅读了 timeit.py,它通过构造一个语句然后使用新的命名空间调用eval()来工作,这些新命名空间(似乎)与你的主命名空间没有连接。请注意,由于sorted是内置的,因此内部的 eval 表达式timeit.repeat()可以访问名称;如果它是你的def,你必须这样做from __main__ import b, myfunc

我希望有比这更合适的方法来达到目的。

于 2010-05-12T15:36:02.177 回答