Python中与内联函数或宏等价的实现

73 投票
7 回答
98191 浏览
提问于 2025-04-16 20:05

我刚刚意识到,执行

x.real*x.real+x.imag*x.imag

的速度是执行

abs(x)**2

的速度快三倍,其中 x 是一个包含复数的 numpy 数组。为了提高代码的可读性,我可以定义一个函数,比如

def abs2(x):
    return x.real*x.real+x.imag*x.imag

这个函数的速度仍然比 abs(x)**2 快很多,但这样做的代价是需要调用这个函数。有没有办法像在 C 语言中使用宏或者 inline 关键字那样,把这个函数内联?

7 个回答

10

我同意大家的看法,这种优化在CPython上只会让你感到痛苦。如果你在意性能,应该考虑使用PyPy(不过我们的NumPy可能还不够完善,没法用)。不过我想说的是,在PyPy上你确实可以关注这些优化,虽然像之前提到的,这个特定的优化PyPy会自动处理。但如果你对PyPy很了解,你真的可以调整你的代码,让PyPy生成你想要的汇编代码,不过其实你几乎不需要这样做。

37

虽然这不是提问者想要的,但还是挺接近的:

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))

在上面的代码中,add_lots_of_numbers 函数被转换成了这样:

def add_lots_of_numbers():
    results = []
    for i in xrange(10):
         results.append(i + i + 1)

另外,对这个问题感兴趣的人,如果想了解在 CPython 中实现这样的优化器的复杂性,也可以看看:

46

我能像在C语言中使用宏或者inline关键字那样,把这样的函数内联吗?

不可以。在执行到这个特定指令之前,Python解释器甚至不知道有没有这样的函数,更别提它具体是干什么的了。

正如评论中提到的,PyPy会自动进行内联(不过上面的说法依然成立——它“只是”在运行时生成一个优化过的版本,利用这个版本,但当这个版本失效时又会退出),不过在这个特定情况下并没有帮助,因为在PyPy上实现NumPy的工作才刚刚开始,至今还没有达到测试阶段。但总的来说:在Python中,不用担心这种层面的优化。要么实现者自己优化,要么就不优化,这不是你的责任。

撰写回答