方法与函数之间的python关系

时间:2019-05-28 13:42:54

标签: python performance

按照https://docs.python.org/3/tutorial/classes.html的教程(请参见下文)来了解我所希望的更深层次的内容

class Foo:
    def bar(self, spam='spam'):
        i = 3**33

x = Foo()
meth = x.bar
func = Foo.bar

%timeit x.bar('spam')      # 1
%timeit meth('spam')       # 2
%timeit func(x, 'spam')    # 3

应按照从慢到快的顺序排列。但这不是,对meth()的调用花费100ns,对func的调用花费110ns(#1比预期的慢)。

从下面的解释中,我会想到,在#2中,方法f必须解压缩到函数和类实例中,然后在该实例之前附加参数列表,并调用该函数。为什么它不比只有普通函数调用的#3慢呢?

怎么了?


  

如果您仍然不了解方法的工作原理,那么看一下实现也许可以澄清问题。当引用实例的非数据属性时,将搜索实例的类。如果名称表示作为函数对象的有效类属性,则通过将实例对象和刚在抽象对象中一起找到的函数对象打包(指向)来创建方法对象:这是方法对象。当使用实参列表调用方法对象时,将从实例对象和实参列表中构造一个新的实参列表,并使用此新的实参列表来调用函数对象。

1 个答案:

答案 0 :(得分:4)

如果您对三个调用中的字节码进行反汇编,则会得到以下信息:

1         0 LOAD_NAME                0 (x)
          2 LOAD_METHOD              1 (bar)
          4 LOAD_CONST               0 ('spam')
          6 CALL_METHOD              1
          8 RETURN_VALUE


1         0 LOAD_NAME                0 (f)
          2 LOAD_CONST               0 ('spam')
          4 CALL_FUNCTION            1
          6 RETURN_VALUE

1         0 LOAD_NAME                0 (Foo)
          2 LOAD_METHOD              1 (bar)
          4 LOAD_NAME                2 (x)
          6 LOAD_CONST               0 ('spam')
          8 CALL_METHOD              2
         10 RETURN_VALUE

您可以看到,第一个和最后一个实际上要完成更多的工作。中间的函数已经拥有了该函数,因此它可以立即调用它(因为您已经使用f = x.bar将其从类中删除了)而其他函数仍然需要在该类中进行字典查找。 / p>