我该如何在Cython中使用`round()`函数?

3 投票
1 回答
3285 浏览
提问于 2025-04-18 07:29

----------更新-------------------------

在这里找到了一些线索 这里

缺点是,官方的64位Python版本没有包含libmsvcr90.a这个文件,而我们需要它来链接正确的C运行时DLL。

-----------原帖-------------------

我的Python版本:

Python 3.3.5,使用的是Windows下的MSC v.1600 64位版本。安装并使用了Windows SDK v7.1。我已经使用Cython工作了一周,似乎其他代码运行得很好。

在这个链接中提到,round()是一个内置函数。然而,当我在Cython代码中调用它,并使用cython my_code.pyx -a来检查时,这个函数显示为纯黄色,意味着使用的是Python的方法。

然后我在网上查了一下,使用了:

from libc.math cimport round

但是在编译时出现了“未解决的外部符号”的错误。

我该怎么办?

这是我的代码:

from libc.math cimport round

cdef float a = 1.5
cdef float b

b = round(a)
print(b)

然后它显示:致命错误 LNK1120:1个未解决的外部错误

我的setup.py:

from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize
import numpy as np

extensions = [
    Extension('test', ['test.pyx'], include_dirs = [np.get_include()]),
    ]

setup(
    ext_modules = cythonize(extensions)
    )

我知道np.get_include()在这种情况下其实不是必须的,但我加上它是因为我经常使用numpy,这样做也没什么坏处。

我编译的命令是:

python setup.py build_ext --inplace

结果(我实际上在我的机器上使用的是setup1.py):

X:\WorkFolder\DataAnalysis\lw9pg\mol>python setup1.py build_ext --inplace
正在运行 build_ext
构建 'test' 扩展
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\Bin\amd64\cl.exe /c /nologo /Ox /MD /W3 /GS- /DNDEBUG -IX:\WinPython3\python-3.3.5.amd64\include -IX:\WinPython3\python-3.3.5.amd64\include /Tctest.c /Fobuild\temp.win-amd64-3.3\Release\test.obj
test.c
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\Bin\amd64\link.exe /DLL /nologo /INCREMENTAL:NO /LIBPATH:X:\WinPython3\python-3.3.5.amd64\libs LIBPATH:X:\WinPython3\python-3.3.5.amd64\PCbuild\amd64 /EXPORT:PyInit_test build\temp.win-amd64-3.3\Release\test.obj /OUT:X:\WorkFolder\DataAnalysis\lw9pg\mol\test.pyd /IMPLIB:build\temp.win-amd64-3.3\Release\
test.lib /MANIFESTFILE:build\temp.win-amd64-3.3\Release\test.pyd.manifest
test.obj : 警告 LNK4197: 导出 'PyInit_test' 被多次指定;使用第一次的定义
创建库 build\temp.win-amd64-3.3\Release\test.lib 和对象 build\temp.win-amd64-3.3\Release\test.exp
test.obj : 错误 LNK2019: 在函数 __pyx_pf_4test_rounding 中引用的未解决外部符号 round
X:\WorkFolder\DataAnalysis\lw9pg\mol\test.pyd : 致命错误 LNK1120: 1个未解决的外部错误
错误:命令 '"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\Bin\amd64\link.exe"' 失败,退出状态112
0

1 个回答

3

如果你想测试简单的cython代码,最简单的方法就是使用 pyximport

假设你的代码文件叫 tester.pyx,你可以这样运行它:

在同一个文件夹里,在一个python文件的顶部加上这段代码,然后直接运行这个文件,你会看到 print b 输出 2.0

import pyximport
pyximport.install()

要编译并运行一个cython函数,我使用以下的setup.py脚本:

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext

ext= Extension("tester", sources=["tester.pyx"])
setup(ext_modules=[ext],cmdclass={'build_ext': build_ext})

用下面的命令在你的 .pyx 文件上运行它, --inplace 参数会把它编译到同一个目录下:

python setup.py build_ext --inplace --compiler=mingw32 # --compiler=mingw32 only needed on windows

你会得到一个 tester.pyd 文件(在mac和linux上是tester.so),你可以像从python模块中导入函数一样导入你的函数。

这是一个简单的函数,用来对一个数字进行四舍五入:

from libc.math cimport round

def rounding(float n):
    return round(n)

我可以 compile 它,或者使用 pyxinstall 导入并运行它,像这样:

In [29]: from tester1 import *

In [30]: rounding(12.3453455)
Out[30]: 12.0

使用pyximport:

In [21]: import pyximport

In [22]: pyximport.install()
Out[22]: (None, None)
         from tester import *
In [23]: rounding(10.23232)
Out[23]: 10.0

我还创建了一个纯python的四舍五入方法来做对比:

def py_rounding(n):
    return round(n)

import timeit
if __name__=='__main__':
    print timeit.timeit('py_rounding(10.23232)','from cyt import py_rounding')
    print timeit.timeit('rounding(10.23232)','from tester import rounding')
    0.183354854584
    0.037761926651

这个 cython 代码的速度明显更快。

这些都是非常基础的例子,你可以在 这里 找到更好的cython用法,包括在ipython中使用 %load_ext cythonmagic

撰写回答