5

知道在 python 中调用函数是昂贵的,这个问题的答案对优化决策有一些影响,例如将直接的单函数数值方法与面向对象的方法进行比较。所以我想知道

  • 所需的函数调用的典型数量是多少?
  • 最少需要多少次函数调用?
  • 什么增加了通话次数?
  • 用户创建的类与内置类相比如何?
  • 对象删除(包括垃圾收集)呢?

我的 google-fu 无法找到这个问题的答案。

编辑:因此,为了总结评论并阻止更接近的投票,这里有一些澄清:

  • 与调用普通 python 函数相比,我对 python 实例创建的时间复杂性感兴趣
  • 出于这个问题的目的,让我们将自己限制在最新的 CPython 版本中。
4

2 回答 2

7

请参阅Eli Bendersky 的Python 对象创建

详细引用结论:

以免我们因树木而失去森林,让我们重新审视本文开头的问题。CPython 执行时会发生什么j = Joe()

  • 由于Joe没有明确的元类,type是它的类型。所以 的tp_calltype,即type_call,被调用。
  • type_call首先调用tp_newJoe 的 slot:
    • 由于 Joe 没有明确的基类,它的基类是object. 因此,object_new被称为。
    • 由于 Joe 是 Python 定义的类,因此它没有自定义tp_alloc插槽。因此,object_new调用PyType_GenericAlloc.
    • PyType_GenericAlloc分配并初始化一块足以容纳 Joe 的内存。
  • type_call然后继续调用Joe.__init__新创建的对象。
    • 由于Joe未定义__init__,因此调用其基数__init__,即object_init
    • object_init什么也没做。
  • 新对象从 name 返回type_call并绑定到 name j
于 2012-07-30T12:31:05.253 回答
3

我已按照评论中的建议完成并用于timeit这些测试用例:

def a():
    pass

class A(object):
    pass

class B(object):
    def __init__(self):
        pass

class NOPType(type):
    pass

class C(object):
    __metaclass__ = NOPType
    def __init__(self):
        pass

class D(object):
    def __new__(cls, *args, **kwargs):
        return super(D, cls).__new__(cls)

    def __init__(self):
        pass

class E(A):
    def __init__(self):
        super(E, self).__init__()

测试结果:

$ python -m timeit -s "import tst" "tst.a()"
10000000 个循环,3 个中最好的:每个循环 0.149 微秒
$ python -m timeit -s "import tst" "tst.A()"
10000000 个循环,3 个中最好的:每个循环 0.169 微秒
$ python -m timeit -s "import tst" "tst.B()"
1000000 个循环,3 个中最好的:每个循环 0.384 微秒
$ python -m timeit -s "import tst" "tst.C()"
1000000 个循环,3 个中最好的:每个循环 0.397 微秒
$ python -m timeit -s "import tst" "tst.D()"
1000000 个循环,3 个中最好的:每个循环 1.09 微秒
$ python -m timeit -s "import tst" "tst.E()"
1000000 个循环,3 个中最好的:每个循环 0.827 微秒

使用函数调用作为基线,结果如下:

  • 一个基本的实例化需要多 1.1 倍的时间。
  • 添加__init__方法将因子增加到 2.6
  • 添加一个无操作元类只是稍微贵一点,在 2.7
  • 而是添加一个 basic __new__,相当于 7.3 的函数调用
  • 具有单个子类的类相当于 5.6 函数调用

如果将调用super替换为其返回值,则对于最后两个结果,您可以减去大约 2。

这应该粗略估计在 CPython 2.7 中耗时的 python 类与 python 函数的比较。

于 2012-07-30T13:09:23.230 回答