如何使用可调用对象作为 timeit.Timer 的设置?

发布于 2024-09-02 00:00:37 字数 972 浏览 5 评论 0原文

我想对一些依赖于某些设置的代码进行计时。设置代码看起来有点像这样:

>>> 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 的内容。

马特

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.TestCase instances into something that can feed right into timeit.Timer.

Matt

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

少跟Wǒ拽 2024-09-09 00:00:37

在 2.6 中,您可以根据 文档“直接执行”

2.6 版中的更改stmt
setup 参数现在也可以采用
无需调用即可调用的对象
论据。这将嵌入调用
它们在计时器函数中
然后由timeit()执行。笔记
时间开销有点
在这种情况下更大,因为
额外的函数调用。

您是否还在使用旧版本的 Python?在这种情况下,我建议采用 Python 2.6 的 timer.py 源代码并将它们“反向移植”到您所使用的版本 - 如果该版本是 2.5,那么应该不难(变得更难)当然,你需要回到过去的距离越远)。我通常不建议将其用于“生产”代码,但对于支持测试、调试、性能测量等的代码来说,它非常好。

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.

A君 2024-09-09 00:00:37

我在这里问了这个问题的一个变体,也得到了一个没有解决我的问题的答案。我相信我们都未能用 Pythonic 的术语来阐明这个问题。

我不知道这是否是一个黑客,解决方法,或者它应该如何完成,但它确实有效:

>>> 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 是内置函数,因此 timeit.repeat() 内的 eval'ed 表达式可以访问该名称;如果它是你的 def,你必须 from __main__ import b, myfunc

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文