【问题标题】:python relation between method and function方法和函数之间的python关系
【发布时间】: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


【解决方案1】:

如果你反汇编来自三个调用的字节码,你会得到以下结果:

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把它从类中拉出来了),而其他的仍然需要在类中进行字典查找。

【讨论】:

  • 感谢您的快速回答 - 什么工具可以进行这样的反汇编?无论如何,这是一个有效的观点,但是不,即使将方法提取到本地名称中也不会使其比 #2 更快,与 100 相比,我得到 110ns
  • 你能解释一下你最后一句话的意思吗?你改变了什么?反汇编是使用标准库的dis 模块完成的
  • 我编辑了这个问题,以避免在比较中进行 dict 查找的时间。 +1 为 dis 模块 - 虽然这不能回答原始问题;)
  • 所以你想知道为什么即使在你改变之后,#3 仍然更慢?在 #3 中还有一个 LOAD_NAME 调用,因为必须加载函数和要调用它的对象。
  • 对……嗯嗯,不过文中说,方法对象是通过将func和x打包在一起,然后在调用方法时再次解包。好吧,我不太确定我的观察是不可能的;)……但这仍然很奇怪……
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-28
相关资源
最近更新 更多