函数定义在另一个函数定义-slow中?

时间:2011-10-19 15:12:47

标签: python performance function closures decorator

看看构造我的函数的两种方法:

class myClass:
    def _myFunc(self):
        pass

    def myFunc2(self):
        self._myFunc()

class myClass:
    def myFunc2(self):
        def myFunc():
            pass

        myFunc()

第二种选择会慢吗? 我只需要从myFunc2调用myFunc,所以我想将它隐藏在我的模块文档中,我可以使用下划线,但我认为将它放在函数中会更清晰。另一方面,我可能需要每秒调用myFunc2几百次,所以每次调用myFunc2时“重新定义”myFunc可能会很慢......这是一个很好的猜测吗?

4 个答案:

答案 0 :(得分:7)

在64位Ubuntu上使用Python 2.6.5,没有明显的区别:

# version 1
In [2]: %timeit c1.myFunc2()
1000000 loops, best of 3: 461 ns per loop

# version 2
In [3]: %timeit c2.myFunc2()
1000000 loops, best of 3: 464 ns per loop

答案 1 :(得分:3)

第二个变体中的局部函数不会反复编译 - 它与整个文件一起编译一次,并且它的主体存储在代码对象中。在执行外部函数期间发生的唯一事情是代码对象被包装在一个新的函数对象中,然后绑定到本地名称myFunc

如果myFunc()采用默认参数,则两种变体之间可能存在差异。他们的定义将在第二个变体中反复执行,从而导致可能的性能损失。

夸张的例子:

from time import sleep

class MyClass:
    def _my_func(self, x=sleep(1)):
        pass
    def my_func2(self):
        self._my_func()

class MyClass2:
    def my_func2(self):
        def my_func(x=sleep(1)):
            pass
        my_func()

使用上面的愚蠢代码,myClass.myFunc2()将立即返回,而myClass2.myFunc2()需要一秒钟才能执行。

答案 2 :(得分:2)

虚线查找(a.k.a.属性绑定)总是比嵌套范围查找更长。前者涉及查找和创建新对象(绑定或未绑定方法)的系列字典。后者使用单元格变量,并使用数组查找实现。

答案 3 :(得分:0)

尽管有其他答案声称没有效果,我想我应该检查一下。 我发现在外部定义函数有一个非常明确的优势。

import random
def ff1(i):
    r1 = random.random()
    r2 = random.random()
    if r1 < 0.5:
        return i*r2
    else:
        return i/r2

def f1(i):
    return ff1(i)

def f2(i):
    def ff2(i):
        r1 = random.random()
        r2 = random.random()
        if r1 < 0.5:
            return i*r2
        else:
            return i/r2
    return ff2(i)
%%timeit -r 10 -n 10 
x = 0.5
for i in xrange(10000):
    x = f1(x)

10个循环,最好10个循环:每循环4.2毫秒

%%timeit -r 10 -n 10
x = 0.5
for i in xrange(10000):
    x = f2(x)

10个循环,最好10个循环:每个循环5.33毫秒

%%timeit -r 1 -n 1 
x = 0.5
for i in xrange(1000000):
    x = f1(x)

1个循环,最好是每个循环1:438 ms

%%timeit -r 1 -n 1
x = 0.5
for i in xrange(1000000):
    x = f2(x)

1个循环,最好是每个循环1:574毫秒