检查这个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中调用它来评估夏天?
答案 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
,然后调用func
(source 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