注意: 我在问是否有一种Python方法可以做到这一点(使用默认args似乎比使用partial更不Python(,以及这两种方法是否有显著的局限性("成本"-我预计时间不会有显著差异,但可能还有其他局限性,我看不到这些局限性会使平衡向一种方法与另一种方法倾斜(
我试图了解在lambda不可行的后期绑定情况下使用"partial"的成本。我已经根据本指南创建了一些示例代码来举例说明这一点。
由于绑定延迟,以下内容无法按预期工作:
def create_thingies():
thingies = []
for i in range(1,6):
def thingy(x):
print("Some output", i)
return i ** (x * i)
thingies.append(thingy)
return thingies
results=[]
for thingy in create_thingies():
results.append(thingy(2))
print(results)
输出:
Some output 5
Some output 5
Some output 5
Some output 5
Some output 5
[9765625, 9765625, 9765625, 9765625, 9765625]
使用"分部"可以避免这个问题,但代价是什么?
from functools import partial
def create_thingies():
thingies = []
for i in range(1,6):
def thingy(i, x):
print("Some output", i)
return i ** (x * i)
thingies.append(partial(thingy, i))
return thingies
results=[]
for thingy in create_thingies():
results.append(thingy(2))
print(results)
输出:
Some output 1
Some output 2
Some output 3
Some output 4
Some output 5
[1, 16, 729, 65536, 9765625]
我在这里看到了很多关于lambda与partial的讨论,,但在lambda工作不好的情况下(一个非常复杂的函数(,如果(具有多个表达式的函数(是partial的话,还有更好的方法可以将其强制转换为lambda表达式吗
使用partial
,不需要为i
的每个值定义thingy
一次,因为thingy
不使用任何自由/全局变量,只使用其参数。
from functools import partial
def thingy(i, x):
print("Some output", i)
return i ** (x * i)
thingies = [partial(thingy, i) for i in range(1,6)]
results = [th(2) for th in thingies]
print(results)
至于成本,您应该了解性能是否可以接受。
这里有一个比较3个选项的快速测试:
import timeit
# The fastest: define a function using a default parameter value
print timeit.timeit('results = [ th(2) for th in create_thingies()]', '''
def create_thingies():
thingies = []
for i in range(1,6):
def thingy(x,i=i):
#print("Some output", i)
return i ** (x * i)
thingies.append(thingy)
return thingies
''')
# The slowest, but IMO the easiest to read.
print timeit.timeit('results = [ th(2) for th in create_thingies()]', '''
def create_thingies():
from functools import partial
def thingy(i,x):
#print("Some output", i)
return i ** (x * i)
return [partial(thingy, i) for i in range(1,6)]
''')
# Only a little slower than the first
print timeit.timeit('results = [ th(2) for th in create_thingies()]', '''
def create_thingies():
def make_thingy(i):
def thingy(x):
#print("Some output", i)
return i ** (x * i)
return thingy
thingies = [make_thingy(i) for i in range(1,6)]
return thingies
''')
在函数创建时使用默认参数nalue绑定值:
def thingy(x, i=i):
print("Some output", i)
return i ** (x * i)
有几种方法可以进行早期绑定。一些最流行的是默认参数、partial
和maker函数。至少在我的python版本的机器上,它们花费的时间大致相同。
以下是如何做到这三点的示例:
import time
from functools import partial
from contextlib import contextmanager
@contextmanager
def timer(what):
t1 = time.time()
yield
print "%-30s: %5d millis" % (what, (time.time() - t1) * 1e3)
N = 5000
print
with timer('create bound'):
thingies = []
for i in xrange(N):
def thingy(x, i=i):
return i ** (x * i)
thingies.append(thingy)
with timer('eval bound'):
for t in thingies:
t(2)
with timer('create partial'):
def thingy(i, x):
return i ** (x * i)
thingies = [partial(thingy, i) for i in xrange(N)]
with timer('eval partial'):
for t in thingies:
t(2)
with timer('create maker'):
def make_thingy(i):
def thingy(x):
return i ** (x * i)
return thingy
thingies = [make_thingy(i) for i in xrange(N)]
with timer('eval maker'):
for t in thingies:
t(2)
以下是我观察到的时间(Python 2.7.6+Windows+Haswell(:
create bound : 5 millis
eval bound : 1861 millis
create partial : 2 millis
eval partial : 1832 millis
create maker : 2 millis
eval maker : 1829 millis
请注意,创建绑定方法的成本更高,但所有3个版本的调用开销都非常接近。
我通常使用分部函数和maker函数的组合,这取决于给定代码的哪一个最清晰。