Python-使用';部分';对于lambda不适用的后期绑定问题-成本与收益?

Python-使用';部分';对于lambda不适用的后期绑定问题-成本与收益?,python,lambda,late-binding,Python,Lambda,Late Binding,注意:我想问的是,是否有一种Pythonic方法可以做到这一点(使用默认参数似乎比使用partial更不适合Pythonic),以及这两种方法是否都有很大的局限性(“成本”)-我不认为时间会有显著差异,但可能存在其他限制,我没有看到这种限制会使平衡朝着一种方法和另一种方法倾斜) 我试图了解在lambda不可行的后期绑定情况下使用“partial”的成本。我创建了一些示例代码来举例说明这一点 由于后期绑定,以下内容无法正常工作: def create_thingies(): thingie

注意:我想问的是,是否有一种Pythonic方法可以做到这一点(使用默认参数似乎比使用partial更不适合Pythonic),以及这两种方法是否都有很大的局限性(“成本”)-我不认为时间会有显著差异,但可能存在其他限制,我没有看到这种限制会使平衡朝着一种方法和另一种方法倾斜)

我试图了解在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]
Some output 1
Some output 2
Some output 3
Some output 4
Some output 5
[1, 16, 729, 65536, 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 5
Some output 5
Some output 5
Some output 5
Some output 5
[9765625, 9765625, 9765625, 9765625, 9765625]
Some output 1
Some output 2
Some output 3
Some output 4
Some output 5
[1, 16, 729, 65536, 9765625]

我在这里看到了很多关于lambda与partial的讨论,但是在lambda根本不能很好地工作的情况下(一个非常复杂的函数),如果有的话(函数的表达式不止一个)部分是一种方法,还是有更好的方法可以将其强制转换为lambda表达式?

使用默认参数nalue在函数创建时绑定值:

def thingy(x, i=i):
    print("Some output", i)
    return i ** (x * i)

使用
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
''')

有几种方法可以进行早期绑定。其中一些最流行的是默认参数、
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):

请注意,创建绑定方法的成本更高,但所有3个版本的调用开销都非常接近


我通常混合使用partials和maker函数,这取决于对于给定的代码位,哪一个函数最清晰。

kindall的答案是我们通常如何做。你是在寻找答案,还是想了解在这种情况下
partial
的用法?我在他们的回答中添加了一条评论。我已经看到lambda比partials(Guido)更受欢迎,但是当lambda不可用时,使用参数副作用比显式部分调用更受欢迎吗?如果是这样,为什么?等等,lambda一点都不受欢迎。Python社区喜欢尽可能远离lambdas。第二,我们使用默认的参数化函数,这是非常好的。在这个问题中,我们不太清楚您想要什么。您是否希望有人将
部分解决方案与其他解决方案进行性能比较?您想要“最具Python风格”的解决方案,还是最简单的编写方法?我们如何评估什么答案可以“解决”您的问题?堆栈溢出不是用来进行开放式讨论的地方。@thefourtheye,这取决于你问谁。。。当()时,我明白这更多的是一种基于默认参数如何工作的副作用的攻击。。。这样做真的很像蟒蛇吗,我个人喜欢它,因为它不需要导入,并且可以清楚地显示签名中绑定了哪些参数。问题已更新-我不希望时间会有所不同,但我想知道使用部分参数和默认参数是否涉及其他因素。看到时间安排很有趣但我更多地考虑了使用部分参数与默认参数的其他成本(或好处)。创客功能理念新颖。。。“我没有考虑到这一点。”MartyMacGyver主要的成本是:时间、内存和可读性。除非您正在创建大量的小函数(在这种情况下,您的应用程序可能非常慢),否则这三个函数都应该具有相似的内存占用。在这三个选项之间,存在特定于应用程序的可读性权衡。局部的通常是最好的,但并不总是最好的。默认参数允许用户稍后覆盖默认值(有时好,有时坏)。等