开发者

How to use a callable as the setup with timeit.Timer?

I want to time some code that depends on some setup. The setup code looks a little like this:

>>> b = range(1, 1001)

And the code I want to time looks vaguely like this:

>>> sorted(b)

Except my code uses a different function than sorted. But that ain't important right now.

Anyhow, I know how to time this code as long as I pass in strings to timeit:

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

How do I use a setup callable and have it put stuff into the namespace that the stmt callable can access?

In other words, how do I do the same thing as the code above, but with callables, and not strings containing callables?

Incidentally, the bigger goal here is to reuse code from my unit tests to measure performance:

import unittest
class TestSorting(unittest.TestCase):

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

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

I expect to do a little work. The timeit setup will need to make an instance of TestSorting and somehow the stmt code will have to use that particular instance.

Once I understand how to have the timeit setup put stuff into the same namespace as the timeit stmt, I'll look into how to translate unittest.Te开发者_C百科stCase instances into something that can feed right into timeit.Timer.

Matt


In 2.6, you can "just do it", per the docs:

Changed in version 2.6: The stmt and setup parameters can now also take objects that are callable without arguments. This will embed calls to them in a timer function that will then be executed by timeit(). Note that the timing overhead is a little larger in this case because of the extra function calls.

Are you stuck using an old version of Python? In that case, I would suggest taking Python 2.6's timer.py sources and "backporting" them to the version you're stuck with -- should not be difficult if that version is 2.5 (gets harder the farther you need to travel back in time, of course). I would generally not recommend this for "production" code, but it's quite fine for code that supports testing, debugging, performance measurements, and the like.


I've asked a variant of this question here and also got an answer that didn't solve my problem. I believe we are both failing to articulate the problem in terms Pythonic.

I don't know if this is a hack, workaround, or how it is supposed to be done, but it does work:

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

I have read timeit.py, it works by constructing a statement and then calls eval() on it using new namespaces which have (seemingly) no connection to your main namespace. Note that since sorted is a built-in, the eval'ed expression inside timeit.repeat() has access to the name; if it was your def you'd have to from __main__ import b, myfunc.

I hope there is more proper way than this to achieve the end.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜