24

我一直在使用 Python,并设置了以下代码情况:

import timeit

setting = """
import functools

def f(a,b,c):
    pass

g = functools.partial(f,c=3)    
h = functools.partial(f,b=5,c=3)   
i = functools.partial(f,a=4,b=5,c=3)
"""

print timeit.timeit('f(4,5,3)', setup = setting, number=100000)
print timeit.timeit('g(4,5)', setup = setting, number=100000)
print timeit.timeit('h(4)', setup = setting, number=100000)
print timeit.timeit('i()', setup = setting, number=100000)

结果我得到以下结果:

f: 0.181384086609
g: 0.39066195488
h: 0.425783157349
i: 0.391901016235

为什么对部分函数的调用需要更长的时间?部分函数只是将参数转发给原始函数还是将静态参数映射到整个过程?而且,在 Python 中是否有一个函数可以返回填充的函数体,因为所有参数都是预定义的,就像函数 i 一样?

4

2 回答 2

26

为什么对部分函数的调用需要更长的时间?

由于额外的函数调用,代码partial需要大约两倍的时间。函数调用很昂贵:

Python 中的函数调用开销相对较高,尤其是与内置函数的执行速度相比。

-

部分函数只是将参数转发给原始函数还是将静态参数映射到整个过程?

据我所知 - 是的,它只是将参数转发给原始函数

-

而且,在 Python 中是否有一个函数可以返回填充的函数体,因为所有参数都是预定义的,就像函数 i 一样?

不,我不知道 Python 中有这样的内置函数。但我认为可以做你想做的事,因为函数是可以复制和修改的对象。

这是一个原型:

import timeit
import types


# http://stackoverflow.com/questions/6527633/how-can-i-make-a-deepcopy-of-a-function-in-python
def copy_func(f, name=None):
    return types.FunctionType(f.func_code, f.func_globals, name or f.func_name,
        f.func_defaults, f.func_closure)


def f(a, b, c):
    return a + b + c


i = copy_func(f, 'i')
i.func_defaults = (4, 5, 3)


print timeit.timeit('f(4,5,3)', setup = 'from __main__ import f', number=100000)
print timeit.timeit('i()', setup = 'from __main__ import i', number=100000)

这使:

0.0257439613342
0.0221881866455
于 2013-06-30T09:31:13.813 回答
8

使用部分应用的参数调用函数的成本更高,因为函数调用的数量增加了一倍。的效果functools.partial()类似于这个例子:

def apply_one_of_two(f, a):
    def g(b):
        return f(a, b)
    return g

这意味着apply_one_of_two()返回一个函数,并且当它被调用时,这会导致原始函数的额外调用f

由于 Python 通常不会对此进行优化,因此它直接转化为额外的运行时工作。

但这不是您的微基准测试中要考虑的唯一因素。您还可以在部分调用中从位置参数切换到关键字参数,这会带来额外的开销。

当您反转原始函数中的参数顺序时,部分调用中不需要关键字参数,然后运行时差异会有所减少,例如:

import timeit

setting = """
import functools

def f(a,b,c):
    pass

g = functools.partial(f, 4)
h = functools.partial(f, 4, 5)
i = functools.partial(f, 4, 5, 3)
"""

print(timeit.timeit('f(4, 5, 3)', setup = setting, number=100000))
print(timeit.timeit('g(5, 3)',    setup = setting, number=100000))
print(timeit.timeit('h(3)',       setup = setting, number=100000))
print(timeit.timeit('i()',        setup = setting, number=100000))

输出(在 Fedora 27/Python 3.6 下的 Intel Skylake i7 上):

0.010069019044749439
0.01681053702486679
0.018060395028442144
0.011366961000021547
于 2018-05-06T07:37:07.297 回答