构建numpy源代码时f2py的用途是什么?
当我列出NumPy源代码中的所有Fortran文件时,我得到了:
./doc/source/f2py/scalar.f
./doc/source/f2py/string.f
./doc/source/f2py/calculate.f
./doc/source/f2py/moddata.f90
./doc/source/f2py/array.f
./doc/source/f2py/allocarr.f90
./doc/source/f2py/extcallback.f
./doc/source/f2py/common.f
./doc/source/f2py/ftype.f
./doc/source/f2py/fib3.f
./doc/source/f2py/callback.f
./doc/source/f2py/fib1.f
./doc/f2py/f2python9-final/src/examples/exp1.f
./doc/f2py/simple.f
./doc/f2py/multiarray/foo.f
./doc/f2py/hello.f
./doc/f2py/ex1/bar.f
./doc/f2py/ex1/foobar-smart.f90
./doc/f2py/ex1/foo.f
./doc/f2py/ex1/arr.f
./doc/f2py/ex1/foobar.f90
./numpy/f2py/tests/src/mixed/foo_fixed.f90
./numpy/f2py/tests/src/mixed/foo_free.f90
./numpy/f2py/tests/src/mixed/foo.f
./numpy/f2py/tests/src/size/foo.f90
./numpy/f2py/tests/src/kind/foo.f90
./numpy/f2py/tests/src/assumed_shape/precision.f90
./numpy/f2py/tests/src/assumed_shape/foo_use.f90
./numpy/f2py/tests/src/assumed_shape/.f2py_f2cmap
./numpy/f2py/tests/src/assumed_shape/foo_free.f90
./numpy/f2py/tests/src/assumed_shape/foo_mod.f90
./numpy/f2py/src/test/bar.f
./numpy/f2py/src/test/foo.f
./numpy/f2py/src/test/foo90.f90
./numpy/f2py/src/test/wrap.f
./numpy/distutils/tests/f2py_ext/src/fib1.f
./numpy/distutils/tests/f2py_f90_ext/include/body.f90
./numpy/distutils/tests/f2py_f90_ext/src/foo_free.f90
所以除了f2py本身,没有其他东西在使用Fortran。我查看了线性代数模块。对于LAPACK,有一个叫做make_lite.py
的文件,它从LAPACK的源代码中提取出必要的子程序,并使用f2c
将它们转换成C语言。那么在创建NumPy的过程中,什么时候创建f2py
是方便的呢?我是不是漏掉了什么?
编辑
结果发现,SciPy里面有很多包都在使用f2py。运行
$ find . -iname '*.f*' | cut -d'/' -f3,4 | uniq
会给我显示出包含Fortran文件的确切目录:
linalg/src
fftpack/src
odr/odrpack
special/cdflib
special/amos
special/mach
special/specfun
integrate/quadpack
integrate/odepack
integrate/dop
integrate/linpack_lite
integrate/mach
sparse/linalg
interpolate/fitpack
optimize/minpack2
optimize/minpack
optimize/nnls
optimize/cobyla
optimize/lbfgsb
optimize/slsqp
stats/mvndst.f
stats/futil.f
stats/statlib
_build_utils/src
lib/lapack
2 个回答
这个问题虽然有点老了,但f2py的目的是让使用numpy的用户能够把自己的Fortran程序包裹起来,然后在Python中调用。我曾经用它来调用我自己写的卡尔曼滤波代码。调用Fortran版本的速度明显比把同样的算法翻译成numpy快,可能是因为涉及了很多数组切片。不过,随着numba的进步,我现在更倾向于在numpy代码上加上@njit装饰器了。
好的,经过一番探索,我觉得我确认了一些最初的猜测。
首先:
原来就是
f2py
自己用到了 Fortran。
正如我在评论中提到的,提问者所说的所有 Fortran 源文件都在 /test/
或 /doc/
目录下,所以我怀疑这些文件是用来测试和记录 f2py
(还有 numpy.distutils
,它使用了 f2py
)。看了一些源文件,似乎也证实了我的想法。f2py
本身看起来是用 Python 和 C 写的。
我查看了线性代数模块。对于 LAPACK,有一个 make_lite.py 文件,它从 LAPACK 源代码中提取必要的子程序,并使用
f2c
转换成 C 代码。
这让我觉得有点奇怪,因为我其实并没有安装 f2c
(还有 Plex
,这个库似乎也是 make_lite.py 所需要的)。我决定在 main()
中加一行代码,看看 make_lite.py
在正常安装过程中是否真的被用到:
...
def main():
# let's see if you're actually doing anything
import subprocess; subprocess.call(['touch', '/tmp/hello_from_make_lite'])
...
果然,在干净的虚拟环境中安装 numpy 后,我的 /tmp/
里没有 hello_from_make_lite
文件,这说明 make_lite.main()
从未执行。看看 numpy/linalg/lapack_lite/README
:
numpy/linalg/blas_lite.c
、numpy/linalg/dlapack_lite.c
和numpy/linalg/zlapack_lite.c
是f2c
转换后的 LAPACK 例程,这些是LinearAlgebra
模块所需的,并被lapack_lite
模块封装。这个目录中的脚本可以用来自动从 LAPACK 源文件目录创建这些文件。
所以 numpy 已经自带了这些 f2c
转换后的 C 源文件——除非你是开发者想要从新版本的 LAPACK 库更新这些函数,否则不需要使用 make_lite.py
。
那么在创建 NumPy 的过程中,什么时候方便创建
f2py
呢?
据我所知,f2py
在正常的 numpy 安装过程中根本没有被用到。我又在 f2py2e.main()
中加了一行:
...
def main():
import subprocess; subprocess.call(['touch', '/tmp/hello_from_f2py2e'])
...
同样,在正常安装 numpy 后,/tmp/hello_from_f2py2e
也不存在。
那么 f2py
实际上是用来干什么的呢?去看看 scipy 的源代码,从根目录调用:
$ find . -iname *.f*
你会看到很多看起来很重要的 Fortran 文件,包括 fftpack
、odepack
、arpack
、fitpack
等等。我怀疑 f2py
主要是用来为 scipy 包装 Fortran 扩展,而不是 numpy。
不过我可能错了——也许 numpy 或 scipy 的开发者会纠正我。
更新
实际上,我觉得 f2py
在正常安装 scipy 的时候也并不需要!如果你查看其中一个 Fortran 模块的源代码目录,比如 fftpack
,你会发现它已经包含了 .pyf
文件,这些文件通常是由 f2py
自动生成的,用来定义 Fortran 函数的接口(见 这里)。
我觉得情况是这样的:f2py
最初是用来生成 Fortran 函数的 .pyf
包装文件的,但这些 .pyf
文件和其他源代码一起分发,所以在正常构建过程中就不需要再运行 f2py
了。