函数闭包与可调用类

2024-10-01 04:46:53 发布

您现在位置:Python中文网/ 问答频道 /正文

在许多情况下,有两种实现选择:闭包和可调用类。例如

class F:
  def __init__(self, op):
    self.op = op
  def __call__(self, arg1, arg2):
    if (self.op == 'mult'):
      return arg1 * arg2
    if (self.op == 'add'):
      return arg1 + arg2
    raise InvalidOp(op)

f = F('add')

或者

^{pr2}$

在做出选择时,应该考虑哪些因素,无论是哪一个方面?在

我能想到两个:

  • 似乎一个闭包总是有更好的性能(不能 想想反例)。

  • 我认为在某些情况下,关闭不能完成任务(例如,如果 它的状态会随着时间而变化)。

我穿对了吗?还有什么可以补充的?在


Tags: selfaddreturnifinitdef情况call
3条回答

请注意,由于之前在我的测试代码中发现了一个错误,我原来的答案是不正确的。修订版如下。

我做了一个小程序来测量运行时间和内存消耗。我创建了以下可调用类和一个闭包:

class CallMe:
    def __init__(self, context):
        self.context = context

    def __call__(self, *args, **kwargs):
        return self.context(*args, **kwargs)

def call_me(func):
    return lambda *args, **kwargs: func(*args, **kwargs)

我定时调用接受不同数量参数的简单函数(math.sqrt()有1个参数,math.pow()有2个参数,max()有12个参数)。在

我在Linux x64上使用了CPython 2.7.10和3.4.3+。我只能在python2上进行内存评测。我使用的源代码是可用的here。在

我的结论是:

  • 闭包的运行速度比等效的可调用类快:在Python2上大约快3倍,但在Python3上只快1.5倍。缩小是因为闭包变慢了,可调用类变慢了。在
  • 闭包比等效的可调用类占用更少的内存:大约是内存的2/3(仅在Python2上测试)。在
  • 虽然不是原始问题的一部分,但有趣的是,通过闭包进行的调用的运行时开销与对math.pow()的调用大致相同,而通过可调用类的运行时开销大约是这个值的两倍。在

这些都是非常粗略的估计,它们可能会因硬件、操作系统和所比较的功能而有所不同。但是,它可以让您了解使用各种可调用的影响。在

因此,这支持了(与我之前写的相反),由@RaymondHettinger给出的接受答案是正确的,并且闭包应该优先用于间接调用,至少只要它不妨碍可读性。另外,感谢@AXO指出了我原始代码中的错误。在

关闭速度更快。类更灵活(也就是说,有更多的方法可用,而不仅仅是调用。在

我知道这是一篇旧文章,但是我没有看到列出的一个因素是,在Python(pre-nonlocal)中,不能修改引用环境中包含的局部变量。(在您的示例中,这样的修改并不重要,但从技术上讲,无法修改这样的变量意味着它不是一个真正的闭包。)

例如,以下代码不起作用:

def counter():
    i = 0
    def f():
        i += 1
        return i
    return f

c = counter()
c()

上面对c的调用将引发UnboundLocalError异常。在

通过使用可变表(如字典)可以轻松解决这一问题:

^{pr2}$

当然,这只是一个变通办法。在

相关问题 更多 >