Python等效于内联函数或宏

Cha*_*net 49 python optimization inline-functions

我刚刚意识到这一点

x.real*x.real+x.imag*x.imag
Run Code Online (Sandbox Code Playgroud)

比做的快三倍

abs(x)**2
Run Code Online (Sandbox Code Playgroud)

其中x是一个复数的numpy数组.为了代码可读性,我可以定义一个类似的函数

def abs2(x):
    return x.real*x.real+x.imag*x.imag
Run Code Online (Sandbox Code Playgroud)

它仍然比abs(x)**2快得多,但它是以函数调用为代价的.是否可以内联这样的函数,就像在C中使用宏或使用内联关键字一样?

小智 34

是否可以内联这样的函数,就像在C中使用宏或使用内联关键字一样?

在达到这个特定指令之前,Python解释器甚至不知道是否存在这样的功能,更不用说它的功能了.

正如评论中所指出的,PyPy 将自动内联(上面仍然保持 - 它"简单地"在运行时生成优化版本,从中受益,但在它失效时突破它),尽管在这种特殊情况下无效因为在PyPy上实现NumPy很快就开始了,直到今天还没有beta级别.但最重要的是:不要担心Python中这个级别的优化.要么实现自己优化它们,要么它们不优化它,这不是你的责任.

  • @ phant0m不确定为什么你们这么多人都喜欢这个引用...它基本上说你不能在不使代码丑陋的情况下进行优化.我只需要内联几次调用,使我的程序速度提高两倍.至少它是值得的... (24认同)
  • 我也觉得有点难以接受最后的评论.这很好,所有这一切都"不是我的责任",但在一天结束的时候,我不能告诉我的老板,如果我的代码错过了性能指标,那就是别人的错. (11认同)
  • +1"不要担心Python中这个级别的优化.要么实现自己优化它们,要么它们不优化,这不是你的响应能力." (7认同)

AXO*_*AXO 14

不完全是OP所要求的,但是关闭:

Inliner内联Python函数调用.此博客文章的概念证明

from inliner import inline

@inline
def add_stuff(x, y):
    return x + y

def add_lots_of_numbers():
    results = []
    for i in xrange(10):
         results.append(add_stuff(i, i+1))
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,add_lots_of_numbers函数被转换为:

def add_lots_of_numbers():
    results = []
    for i in xrange(10):
         results.append(i + i + 1)
Run Code Online (Sandbox Code Playgroud)

任何对这个问题感兴趣的人以及在CPython中实现这样的优化器所涉及的复杂性,也可能想看看:

  • 抱歉,您的解决方案和问题有什么区别? (2认同)
  • @RogerS,OP询问了一些类似于C宏(内联关键字)的东西,它们非常灵活和高效。该库有一些[限制](https://tomforb.es/automatically-inline-python-function-calls/#limitations)并且具有启动时间成本,但除此之外,它执行问题所要求的操作。 (2认同)

Ale*_*nor 7

我同意其他人的看法,这样的优化只会让你对CPython感到痛苦,如果你关心性能,你应该考虑PyPy(虽然我们的NumPy可能太不完整而无用).但是我不同意并且说你可以关心PyPy上的这种优化,而不是特别说明PyPy会自动执行此操作,但是如果你很了解PyPy,你真的可以调整你的代码以使PyPy发出你想要的程序集,不是你几乎需要的.


Tha*_*Tyl 6

没有.

最接近C宏的是一个脚本(awk或其他),你可以包含在一个makefile中,它用你的python脚本中的abs(x)**2替换某个模式.

  • ......这是一个可怕的想法,很多额外的工作和一个不可思议的破损几乎零实际收益的机会. (18认同)
  • 他没有声称这是个好主意.从技术上讲,他是对的. (9认同)

eat*_*eat 6

实际上,它的计算可能甚至更快,例如:

x.real** 2+ x.imag** 2
Run Code Online (Sandbox Code Playgroud)

因此,函数调用的额外成本可能会减少。让我们来看看:

In []: n= 1e4
In []: x= randn(n, 1)+ 1j* rand(n, 1)
In []: %timeit x.real* x.real+ x.imag* x.imag
10000 loops, best of 3: 100 us per loop
In []: %timeit x.real** 2+ x.imag** 2
10000 loops, best of 3: 77.9 us per loop
Run Code Online (Sandbox Code Playgroud)

并将计算封装在一个函数中:

In []: def abs2(x):
   ..:     return x.real** 2+ x.imag** 2
   ..: 
In []: %timeit abs2(x)
10000 loops, best of 3: 80.1 us per loop
Run Code Online (Sandbox Code Playgroud)

无论如何(如其他人所指出的那样),这种微优化(以避免函数调用)并不是真正有效的编写python代码的方法。