Timeit和Partials

时间:2014-12-29 20:30:34

标签: python partial timeit functools

检查这个python代码:

 from functools import partial
 def summer(x, y):
      return x+y

 >>>partial(summer, 1, 2)
 <functools.partial object at 0x10e648628>

然而,当我通过部分时间时间时:

  import timeit
  min(timeit.repeat(partial(summer, 1, 2)))

似乎用x = 1和y = 2评估夏天。

我能理解发生了什么吗?我使用timeit吧?当我为每个参数传递值时,如何评价夏天?

编辑:为了清楚起见,我在下面添加了以下评论。

我的问题是部分(夏天,1,2)不评估夏天。那么为什么在timeit.repeat中调用它来评估夏天?

1 个答案:

答案 0 :(得分:2)

在Python function对象中"first-class" objects。它们可以像任何其他对象一样作为参数传递给函数。在这种情况下, timeit.repeat正在传递函数对象partial(summer, 1, 2),以便稍后在repeat内部可以调用和定时函数对象。

partial(summer, 1, 2)本身是另一个将函数(summer)作为参数传递给另一个函数(partial)的示例。由于您还不想调用summer,因此您想要传递函数对象是有道理的。相反,您希望partial返回的函数对象可以访问summer,以便稍后在调用该函数对象时调用它。


partial(summer, 1, 2)返回一个函数对象:

In [36]: partial(summer, 1, 2)
Out[36]: <functools.partial at 0x7ff31f0bd3c0>

如您所知,要调用该函数,您需要在函数后面放置括号:

In [37]: partial(summer, 1, 2)()
Out[37]: 3

通常当我使用timeit时,我会将语句stmt传递给timeit函数作为字符串:

In [41]: func = partial(summer, 1, 2)

In [42]: timeit.repeat('func()', 'from __main__ import func')
Out[42]: [0.11481308937072754, 0.10448503494262695, 0.1048579216003418]

但是,你是正确的,也可以传递一个可调用的(如函数对象)作为第一个参数:

timeit.repeat(func) 

repeat会致电func并为结果计时。您可以通过使用repeat之类的调试器逐步执行代码来了解pdb如何处理此案例:

import pdb
pdb.set_trace()
timeit.repeat(func)

timeit.py around line 140的代码中,您会看到:

    elif callable(stmt):
        self.src = None
        if isinstance(setup, str):
            _setup = setup
            def setup():
                exec(_setup, global_ns, local_ns)

检查是否stmt,第一个参数是可调用的。如果是,则将func设置为stmt,然后调用funcsource code)。

def inner(_it, _timer, _func=func):
    setup()
    _t0 = _timer()
    for _i in _it:
        _func()       # <--- The function call happens here
    _t1 = _timer()
    return _t1 - _t0
return inner