【发布时间】:2019-05-28 13:42:53
【问题描述】:
按照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 慢。
怎么了?
如果您仍然不了解方法的工作原理,那么看看实现也许可以澄清问题。当引用实例的非数据属性时,将搜索实例的类。如果名称表示作为函数对象的有效类属性,则通过将实例对象和刚刚在抽象对象中找到的函数对象打包(指向)来创建方法对象:这就是方法对象。当使用参数列表调用方法对象时,会从实例对象和参数列表构造一个新的参数列表,并使用这个新的参数列表调用函数对象。
【问题讨论】:
-
您是多次运行并取平均时间,还是只是假设单次运行的运行时间?
-
%timeit自己选择这个(它执行了 1e7 循环并显示了 3 次运行中最好的),但无论如何,是的,这是可重现的,似乎不是缓存问题跨度> -
“当引用实例的非数据属性时”调用
meth不会这样做。 -
是的,这就是为什么 #1 比较慢,我明白了 :) 但是请继续阅读,最后一句,关于构建一个新的参数列表 - 这不应该比情况 #3 更快,这是未完成
-
为什么你认为构造参数列表对于 #2 和 #3 的工作方式不同?
标签: python performance