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